forked from MapComplete/MapComplete
Fix #1794
This commit is contained in:
parent
ad5b5128c0
commit
b8bd13834e
2 changed files with 35 additions and 25 deletions
|
@ -3,7 +3,6 @@ import { MangroveReviews, Review } from "mangrove-reviews-typescript"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { Feature, Position } from "geojson"
|
import { Feature, Position } from "geojson"
|
||||||
import { GeoOperations } from "../GeoOperations"
|
import { GeoOperations } from "../GeoOperations"
|
||||||
import ScriptUtils from "../../../scripts/ScriptUtils"
|
|
||||||
|
|
||||||
export class MangroveIdentity {
|
export class MangroveIdentity {
|
||||||
private readonly keypair: UIEventSource<CryptoKeyPair> = new UIEventSource<CryptoKeyPair>(
|
private readonly keypair: UIEventSource<CryptoKeyPair> = new UIEventSource<CryptoKeyPair>(
|
||||||
|
@ -28,7 +27,7 @@ export class MangroveIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setKeypair(data: string) {
|
private async setKeypair(data: string) {
|
||||||
console.log("Setting keypair from", data)
|
console.debug("Setting keypair from", data)
|
||||||
const keypair = await MangroveReviews.jwkToKeypair(JSON.parse(data))
|
const keypair = await MangroveReviews.jwkToKeypair(JSON.parse(data))
|
||||||
this.keypair.setData(keypair)
|
this.keypair.setData(keypair)
|
||||||
const pem = await MangroveReviews.publicToPem(keypair.publicKey)
|
const pem = await MangroveReviews.publicToPem(keypair.publicKey)
|
||||||
|
@ -80,7 +79,6 @@ export class MangroveIdentity {
|
||||||
|
|
||||||
public getGeoReviews(): Store<(Review & { kid: string; signature: string })[] | undefined> {
|
public getGeoReviews(): Store<(Review & { kid: string; signature: string })[] | undefined> {
|
||||||
if (!this.geoReviewsById) {
|
if (!this.geoReviewsById) {
|
||||||
const all = this.getAllReviews()
|
|
||||||
this.geoReviewsById = this.getAllReviews().mapD((reviews) =>
|
this.geoReviewsById = this.getAllReviews().mapD((reviews) =>
|
||||||
reviews.filter((review) => {
|
reviews.filter((review) => {
|
||||||
try {
|
try {
|
||||||
|
@ -112,12 +110,12 @@ export class MangroveIdentity {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const allReviews = await MangroveReviews.getReviews({
|
const allReviews = await MangroveReviews.getReviews({
|
||||||
kid: pem,
|
kid: pem
|
||||||
})
|
})
|
||||||
this.allReviewsById.setData(
|
this.allReviewsById.setData(
|
||||||
allReviews.reviews.map((r) => ({
|
allReviews.reviews.map((r) => ({
|
||||||
...r,
|
...r,
|
||||||
...r.payload,
|
...r.payload
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -130,7 +128,9 @@ export class MangroveIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks all reviews of a given feature, allows to create a new review
|
* Tracks all reviews of a given feature, allows to create a new review (and inserts this into the list)
|
||||||
|
*
|
||||||
|
* This object will start fetching the reviews as soon as it is constructed
|
||||||
*/
|
*/
|
||||||
export default class FeatureReviews {
|
export default class FeatureReviews {
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +169,9 @@ export default class FeatureReviews {
|
||||||
this._testmode = testmode ?? new ImmutableStore(false)
|
this._testmode = testmode ?? new ImmutableStore(false)
|
||||||
const nameKey = options?.nameKey ?? "name"
|
const nameKey = options?.nameKey ?? "name"
|
||||||
|
|
||||||
if (feature.geometry.type === "Point") {
|
if (options.uncertaintyRadius) {
|
||||||
|
this._uncertainty = options.uncertaintyRadius
|
||||||
|
} else if (feature.geometry.type === "Point") {
|
||||||
this._uncertainty = options?.uncertaintyRadius ?? 10
|
this._uncertainty = options?.uncertaintyRadius ?? 10
|
||||||
} else {
|
} else {
|
||||||
let coordss: Position[][]
|
let coordss: Position[][]
|
||||||
|
@ -180,6 +182,10 @@ export default class FeatureReviews {
|
||||||
feature.geometry.type === "Polygon"
|
feature.geometry.type === "Polygon"
|
||||||
) {
|
) {
|
||||||
coordss = feature.geometry.coordinates
|
coordss = feature.geometry.coordinates
|
||||||
|
}else if(feature.geometry.type === "MultiPolygon"){
|
||||||
|
coordss = feature.geometry.coordinates[0]
|
||||||
|
}else{
|
||||||
|
throw "Invalid feature type: "+feature.geometry.type
|
||||||
}
|
}
|
||||||
let maxDistance = 0
|
let maxDistance = 0
|
||||||
for (const coords of coordss) {
|
for (const coords of coordss) {
|
||||||
|
@ -191,16 +197,15 @@ export default class FeatureReviews {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._uncertainty = options?.uncertaintyRadius ?? maxDistance
|
this._uncertainty = maxDistance
|
||||||
}
|
}
|
||||||
this._name = tagsSource.map((tags) => tags[nameKey] ?? options?.fallbackName)
|
this._name = tagsSource.map((tags) => tags[nameKey] ?? options?.fallbackName)
|
||||||
|
|
||||||
this.subjectUri = this.ConstructSubjectUri()
|
this.subjectUri = this.ConstructSubjectUri()
|
||||||
|
|
||||||
const self = this
|
|
||||||
this.subjectUri.addCallbackAndRunD(async (sub) => {
|
this.subjectUri.addCallbackAndRunD(async (sub) => {
|
||||||
const reviews = await MangroveReviews.getReviews({ sub })
|
const reviews = await MangroveReviews.getReviews({ sub })
|
||||||
self.addReviews(reviews.reviews)
|
this.addReviews(reviews.reviews)
|
||||||
})
|
})
|
||||||
/* We also construct all subject queries _without_ encoding the name to work around a previous bug
|
/* We also construct all subject queries _without_ encoding the name to work around a previous bug
|
||||||
* See https://github.com/giggls/opencampsitemap/issues/30
|
* See https://github.com/giggls/opencampsitemap/issues/30
|
||||||
|
@ -208,7 +213,7 @@ export default class FeatureReviews {
|
||||||
this.ConstructSubjectUri(true).addCallbackAndRunD(async (sub) => {
|
this.ConstructSubjectUri(true).addCallbackAndRunD(async (sub) => {
|
||||||
try {
|
try {
|
||||||
const reviews = await MangroveReviews.getReviews({ sub })
|
const reviews = await MangroveReviews.getReviews({ sub })
|
||||||
self.addReviews(reviews.reviews)
|
this.addReviews(reviews.reviews)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not fetch reviews for partially incorrect query ", sub)
|
console.log("Could not fetch reviews for partially incorrect query ", sub)
|
||||||
}
|
}
|
||||||
|
@ -234,6 +239,11 @@ export default class FeatureReviews {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a featureReviewsFor or fetches it from the cache
|
* Construct a featureReviewsFor or fetches it from the cache
|
||||||
|
*
|
||||||
|
* @param feature The feature that we want reviews of. Various properties are used to link reviews to the feature, namely the centerpoint and size and optionally the name
|
||||||
|
* @param tagsSource Dynamic tags of the feature
|
||||||
|
* @param mangroveIdentity Identity with which new REviews will be mad
|
||||||
|
* @param options If options.nameKey is given, this key will be used as subject to fetch reviews
|
||||||
*/
|
*/
|
||||||
public static construct(
|
public static construct(
|
||||||
feature: Feature,
|
feature: Feature,
|
||||||
|
@ -278,7 +288,7 @@ export default class FeatureReviews {
|
||||||
}
|
}
|
||||||
const r: Review = {
|
const r: Review = {
|
||||||
sub: this.subjectUri.data,
|
sub: this.subjectUri.data,
|
||||||
...review,
|
...review
|
||||||
}
|
}
|
||||||
const keypair: CryptoKeyPair = await this._identity.getKeypair()
|
const keypair: CryptoKeyPair = await this._identity.getKeypair()
|
||||||
const jwt = await MangroveReviews.signReview(keypair, r)
|
const jwt = await MangroveReviews.signReview(keypair, r)
|
||||||
|
@ -293,7 +303,7 @@ export default class FeatureReviews {
|
||||||
...r,
|
...r,
|
||||||
kid,
|
kid,
|
||||||
signature: jwt,
|
signature: jwt,
|
||||||
madeByLoggedInUser: new ImmutableStore(true),
|
madeByLoggedInUser: new ImmutableStore(true)
|
||||||
}
|
}
|
||||||
this._reviews.data.push(reviewWithKid)
|
this._reviews.data.push(reviewWithKid)
|
||||||
this._reviews.ping()
|
this._reviews.ping()
|
||||||
|
@ -306,8 +316,7 @@ export default class FeatureReviews {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private addReviews(reviews: { payload: Review; kid: string; signature: string }[]) {
|
private addReviews(reviews: { payload: Review; kid: string; signature: string }[]) {
|
||||||
const self = this
|
const alreadyKnown = new Set(this._reviews.data.map((r) => r.rating + " " + r.opinion))
|
||||||
const alreadyKnown = new Set(self._reviews.data.map((r) => r.rating + " " + r.opinion))
|
|
||||||
|
|
||||||
let hasNew = false
|
let hasNew = false
|
||||||
for (const reviewData of reviews) {
|
for (const reviewData of reviews) {
|
||||||
|
@ -335,20 +344,20 @@ export default class FeatureReviews {
|
||||||
if (alreadyKnown.has(key)) {
|
if (alreadyKnown.has(key)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
self._reviews.data.push({
|
this._reviews.data.push({
|
||||||
...review,
|
...review,
|
||||||
kid: reviewData.kid,
|
kid: reviewData.kid,
|
||||||
signature: reviewData.signature,
|
signature: reviewData.signature,
|
||||||
madeByLoggedInUser: this._identity.getKeyId().map((user_key_id) => {
|
madeByLoggedInUser: this._identity.getKeyId().map((user_key_id) => {
|
||||||
return reviewData.kid === user_key_id
|
return reviewData.kid === user_key_id
|
||||||
}),
|
})
|
||||||
})
|
})
|
||||||
hasNew = true
|
hasNew = true
|
||||||
}
|
}
|
||||||
if (hasNew) {
|
if (hasNew) {
|
||||||
self._reviews.data.sort((a, b) => b.iat - a.iat) // Sort with most recent first
|
this._reviews.data.sort((a, b) => b.iat - a.iat) // Sort with most recent first
|
||||||
|
|
||||||
self._reviews.ping()
|
this._reviews.ping()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,16 +365,17 @@ export default class FeatureReviews {
|
||||||
* Gets an URI which represents the item in a mangrove-compatible way
|
* Gets an URI which represents the item in a mangrove-compatible way
|
||||||
*
|
*
|
||||||
* See https://mangrove.reviews/standard#mangrove-core-uri-schemes
|
* See https://mangrove.reviews/standard#mangrove-core-uri-schemes
|
||||||
* @constructor
|
|
||||||
*/
|
*/
|
||||||
private ConstructSubjectUri(dontEncodeName: boolean = false): Store<string> {
|
private ConstructSubjectUri(dontEncodeName: boolean = false): Store<string> {
|
||||||
// https://www.rfc-editor.org/rfc/rfc5870#section-3.4.2
|
// https://www.rfc-editor.org/rfc/rfc5870#section-3.4.2
|
||||||
// `u` stands for `uncertainty`, https://www.rfc-editor.org/rfc/rfc5870#section-3.4.3
|
// `u` stands for `uncertainty`, https://www.rfc-editor.org/rfc/rfc5870#section-3.4.3
|
||||||
const self = this
|
return this._name.map(name => {
|
||||||
return this._name.map(function (name) {
|
let uri = `geo:${this._lat},${this._lon}?u=${Math.round(this._uncertainty)}`
|
||||||
let uri = `geo:${self._lat},${self._lon}?u=${Math.round(self._uncertainty)}`
|
|
||||||
if (name) {
|
if (name) {
|
||||||
uri += "&q=" + (dontEncodeName ? name : encodeURIComponent(name))
|
uri += "&q=" + (dontEncodeName ? name : encodeURIComponent(name))
|
||||||
|
}else if(this._uncertainty > 1000){
|
||||||
|
console.error("Not fetching reviews. Only got a point and a very big uncertainty range ("+this._uncertainty+"), so you'd probably only get garbage. Specify a name")
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
return uri
|
return uri
|
||||||
})
|
})
|
||||||
|
|
|
@ -651,13 +651,13 @@ console.log(">>> ",helpTexts.join("\n\n"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
funcName: "rating",
|
funcName: "rating",
|
||||||
docs: "Shows stars which represent the avarage rating on mangrove.reviews",
|
docs: "Shows stars which represent the average rating on mangrove.",
|
||||||
needsUrls: [MangroveReviews.ORIGINAL_API],
|
needsUrls: [MangroveReviews.ORIGINAL_API],
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
name: "subjectKey",
|
name: "subjectKey",
|
||||||
defaultValue: "name",
|
defaultValue: "name",
|
||||||
doc: "The key to use to determine the subject. If specified, the subject will be <b>tags[subjectKey]</b>"
|
doc: "The key to use to determine the subject. If the value is specified, the subject will be <b>tags[subjectKey]</b> and will use this to filter the reviews."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fallback",
|
name: "fallback",
|
||||||
|
|
Loading…
Reference in a new issue