Merge develop

This commit is contained in:
Pieter Vander Vennet 2024-02-21 19:17:42 +01:00
commit 7c5170da15
193 changed files with 4011 additions and 4462 deletions

View file

@ -788,7 +788,7 @@ export class GeoOperations {
return undefined
}
return GeoOperations.centerpointCoordinates(feature)
case "polygon_centerpoint":
case "polygon_centroid":
if (feature.geometry.type === "Polygon") {
return GeoOperations.centerpointCoordinates(feature)
}
@ -817,7 +817,7 @@ export class GeoOperations {
}
return undefined
default:
throw "Unkown location type: " + location
throw "Unkown location type: " + location+" for feature "+feature.properties.id
}
}

View file

@ -10,6 +10,8 @@ import { WikidataImageProvider } from "./WikidataImageProvider"
* A generic 'from the interwebz' image picker, without attribution
*/
export default class AllImageProviders {
private static dontLoadFromPrefixes = ["https://photos.app.goo.gl/"]
public static ImageAttributionSource: ImageProvider[] = [
Imgur.singleton,
Mapillary.singleton,
@ -19,7 +21,8 @@ export default class AllImageProviders {
[].concat(
...Imgur.defaultValuePrefix,
...WikimediaImageProvider.commonsPrefixes,
...Mapillary.valuePrefixes
...Mapillary.valuePrefixes,
...AllImageProviders.dontLoadFromPrefixes
)
),
]

View file

@ -25,7 +25,7 @@ export default class MetaTagging {
>()
constructor(state: {
readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }>
readonly selectedElement: Store<Feature>
readonly layout: LayoutConfig
readonly osmObjectDownloader: OsmObjectDownloader
readonly perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer>
@ -61,7 +61,8 @@ export default class MetaTagging {
})
}
state.selectedElementAndLayer.addCallbackAndRunD(({ feature, layer }) => {
state.selectedElement.addCallbackAndRunD((feature) => {
const layer = state.layout.getMatchingLayer(feature.properties)
// Force update the tags of the currently selected element
MetaTagging.addMetatags(
[feature],

View file

@ -114,7 +114,8 @@ export default class UserRelatedState {
)
this.mangroveIdentity = new MangroveIdentity(
this.osmConnection.GetLongPreference("identity", "mangrove")
this.osmConnection.GetLongPreference("identity", "mangrove"),
this.osmConnection.GetPreference("identity-creation-date", "mangrove")
)
this.preferredBackgroundLayer = this.osmConnection.GetPreference(
"preferred-background-layer",
@ -364,7 +365,7 @@ export default class UserRelatedState {
[translationMode]
)
this.mangroveIdentity.getKeyId().addCallbackAndRun(kid => {
this.mangroveIdentity.getKeyId().addCallbackAndRun((kid) => {
amendedPrefs.data["mangrove_kid"] = kid
amendedPrefs.ping()
})

View file

@ -432,6 +432,6 @@ export class And extends TagsFilter {
}
asMapboxExpression(): ExpressionSpecification {
return ["all", ...this.and.map(t => t.asMapboxExpression())]
return ["all", ...this.and.map((t) => t.asMapboxExpression())]
}
}

View file

@ -13,7 +13,7 @@ export default class ComparingTag implements TagsFilter {
key: string,
predicate: (value: string | undefined) => boolean,
representation: "<" | ">" | "<=" | ">=",
boundary: string,
boundary: string
) {
this._key = key
this._predicate = predicate

View file

@ -291,6 +291,6 @@ export class Or extends TagsFilter {
}
asMapboxExpression(): ExpressionSpecification {
return ["any", ...this.or.map(t => t.asMapboxExpression())]
return ["any", ...this.or.map((t) => t.asMapboxExpression())]
}
}

View file

@ -360,8 +360,8 @@ export class RegexTag extends TagsFilter {
}
asMapboxExpression(): ExpressionSpecification {
if(typeof this.key=== "string" && typeof this.value === "string" ) {
return [this.invert ? "!=" : "==", ["get",this.key], this.value]
if (typeof this.key === "string" && typeof this.value === "string") {
return [this.invert ? "!=" : "==", ["get", this.key], this.value]
}
throw "TODO"
}

View file

@ -65,7 +65,7 @@ export class Tag extends TagsFilter {
asOverpass(): string[] {
if (this.value === "") {
// NOT having this key
return ["[!\"" + this.key + "\"]"]
return ['[!"' + this.key + '"]']
}
return [`["${this.key}"="${this.value}"]`]
}
@ -83,7 +83,7 @@ export class Tag extends TagsFilter {
asHumanString(
linkToWiki?: boolean,
shorten?: boolean,
currentProperties?: Record<string, string>,
currentProperties?: Record<string, string>
) {
let v = this.value
if (typeof v !== "string") {
@ -170,12 +170,7 @@ export class Tag extends TagsFilter {
asMapboxExpression(): ExpressionSpecification {
if (this.value === "") {
return [
"any",
["!", ["has", this.key]],
["==", ["get", this.key], ""],
]
return ["any", ["!", ["has", this.key]], ["==", ["get", this.key], ""]]
}
return ["==", ["get", this.key], this.value]
}

View file

@ -6,11 +6,16 @@ import { GeoOperations } from "../GeoOperations"
export class MangroveIdentity {
private readonly keypair: Store<CryptoKeyPair>
private readonly mangroveIdentity: UIEventSource<string>
/**
* Same as the one in the user settings
*/
public readonly mangroveIdentity: UIEventSource<string>
private readonly key_id: Store<string>
private readonly _mangroveIdentityCreationDate: UIEventSource<string>
constructor(mangroveIdentity: UIEventSource<string>) {
constructor(mangroveIdentity: UIEventSource<string>, mangroveIdentityCreationDate: UIEventSource<string>) {
this.mangroveIdentity = mangroveIdentity
this._mangroveIdentityCreationDate = mangroveIdentityCreationDate
const key_id = new UIEventSource<string>(undefined)
this.key_id = key_id
const keypairEventSource = new UIEventSource<CryptoKeyPair>(undefined)
@ -24,8 +29,6 @@ export class MangroveIdentity {
const pem = await MangroveReviews.publicToPem(keypair.publicKey)
key_id.setData(pem)
})
}
/**
@ -33,27 +36,28 @@ export class MangroveIdentity {
* Is written into the UIEventsource, which was passed into the constructor
* @constructor
*/
private static async CreateIdentity(identity: UIEventSource<string>): Promise<void> {
private async CreateIdentity(): Promise<void> {
const keypair = await MangroveReviews.generateKeypair()
const jwk = await MangroveReviews.keypairToJwk(keypair)
if ((identity.data ?? "") !== "") {
if ((this.mangroveIdentity.data ?? "") !== "") {
// Identity has been loaded via osmPreferences by now - we don't overwrite
return
}
console.log("Creating a new Mangrove identity!")
identity.setData(JSON.stringify(jwk))
this.mangroveIdentity.setData(JSON.stringify(jwk))
this._mangroveIdentityCreationDate.setData(new Date().toISOString())
}
/**
* Only called to create a review.
*/
async getKeypair(): Promise<CryptoKeyPair> {
if(this.keypair.data ?? "" === ""){
if (this.keypair.data ?? "" === "") {
// We want to create a review, but it seems like no key has been setup at this moment
// We create the key
try {
if (!Utils.runningFromConsole && (this.mangroveIdentity.data ?? "") === "") {
await MangroveIdentity.CreateIdentity(this.mangroveIdentity)
await this.CreateIdentity()
}
} catch (e) {
console.error("Could not create identity: ", e)
@ -66,33 +70,36 @@ export class MangroveIdentity {
return this.key_id
}
private allReviewsById : UIEventSource<(Review & {kid: string, signature: string})[]>= undefined
private allReviewsById: UIEventSource<(Review & { kid: string; signature: string })[]> =
undefined
/**
* Gets all reviews that are made for the current identity.
*/
public getAllReviews(): Store<(Review & {kid: string, signature: string})[]>{
if(this.allReviewsById !== undefined){
public getAllReviews(): Store<(Review & { kid: string; signature: string })[]> {
if (this.allReviewsById !== undefined) {
return this.allReviewsById
}
this.allReviewsById = new UIEventSource( [])
this.key_id.map(pem => {
if(pem === undefined){
this.allReviewsById = new UIEventSource([])
this.key_id.map((pem) => {
if (pem === undefined) {
return []
}
MangroveReviews.getReviews({
kid: pem
}).then(allReviews => {
this.allReviewsById.setData(allReviews.reviews.map(r => ({
...r, ...r.payload
})))
kid: pem,
}).then((allReviews) => {
this.allReviewsById.setData(
allReviews.reviews.map((r) => ({
...r,
...r.payload,
}))
)
})
})
return this.allReviewsById
}
addReview(review: Review & {kid, signature}) {
addReview(review: Review & { kid; signature }) {
this.allReviewsById?.setData(this.allReviewsById?.data?.concat([review]))
}
}
@ -122,7 +129,7 @@ export default class FeatureReviews {
private constructor(
feature: Feature,
tagsSource: UIEventSource<Record<string, string>>,
mangroveIdentity?: MangroveIdentity,
mangroveIdentity: MangroveIdentity,
options?: {
nameKey?: "name" | string
fallbackName?: string
@ -131,8 +138,7 @@ export default class FeatureReviews {
) {
const centerLonLat = GeoOperations.centerpointCoordinates(feature)
;[this._lon, this._lat] = centerLonLat
this._identity =
mangroveIdentity ?? new MangroveIdentity(new UIEventSource<string>(undefined))
this._identity = mangroveIdentity
const nameKey = options?.nameKey ?? "name"
if (feature.geometry.type === "Point") {
@ -225,8 +231,15 @@ export default class FeatureReviews {
* The given review is uploaded to mangrove.reviews and added to the list of known reviews
*/
public async createReview(review: Omit<Review, "sub">): Promise<void> {
if(review.opinion !== undefined && review.opinion.length > FeatureReviews .REVIEW_OPINION_MAX_LENGTH){
throw "Opinion too long, should be at most "+FeatureReviews.REVIEW_OPINION_MAX_LENGTH+" characters long"
if (
review.opinion !== undefined &&
review.opinion.length > FeatureReviews.REVIEW_OPINION_MAX_LENGTH
) {
throw (
"Opinion too long, should be at most " +
FeatureReviews.REVIEW_OPINION_MAX_LENGTH +
" characters long"
)
}
const r: Review = {
sub: this.subjectUri.data,
@ -242,13 +255,11 @@ export default class FeatureReviews {
signature: jwt,
madeByLoggedInUser: new ImmutableStore(true),
}
this._reviews.data.push( reviewWithKid)
this._reviews.data.push(reviewWithKid)
this._reviews.ping()
this._identity.addReview(reviewWithKid)
}
/**
* Adds given reviews to the 'reviews'-UI-eventsource
* @param reviews

View file

@ -115,7 +115,6 @@ export default class ThemeViewStateHashActor {
""
)
selectedElement.setData(found)
state.selectedLayer.setData(layer)
return true
}