Skip to content

Commit

Permalink
Layers uuid2 (#2259)
Browse files Browse the repository at this point in the history
Rebase of #2233
  • Loading branch information
yohanboniface authored Nov 15, 2024
2 parents 8c2a0ec + 7dadb83 commit 8105376
Show file tree
Hide file tree
Showing 19 changed files with 282 additions and 114 deletions.
19 changes: 19 additions & 0 deletions umap/migrations/0023_alter_datalayer_uuid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.1.2 on 2024-11-15 11:03

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("umap", "0022_add_team"),
]

operations = [
migrations.AlterField(
model_name="datalayer",
name="uuid",
field=models.UUIDField(
editable=False, primary_key=True, serialize=False, unique=True
),
),
]
22 changes: 15 additions & 7 deletions umap/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def preview_settings(self):
"hash": False,
"scrollWheelZoom": False,
"noControl": True,
"umap_id": self.pk,
"id": self.pk,
"schema": self.extra_schema,
"slideshow": {},
}
Expand Down Expand Up @@ -444,9 +444,7 @@ class DataLayer(NamedModel):
(COLLABORATORS, _("Editors and team only")),
(OWNER, _("Owner only")),
)
uuid = models.UUIDField(
unique=True, primary_key=True, default=uuid.uuid4, editable=False
)
uuid = models.UUIDField(unique=True, primary_key=True, editable=False)
old_id = models.IntegerField(null=True, blank=True)
map = models.ForeignKey(Map, on_delete=models.CASCADE)
description = models.TextField(blank=True, null=True, verbose_name=_("description"))
Expand Down Expand Up @@ -525,12 +523,13 @@ def metadata(self, request=None):
obj["id"] = self.pk
obj["permissions"] = {"edit_status": self.edit_status}
obj["editMode"] = "advanced" if self.can_edit(request) else "disabled"
obj["_referenceVersion"] = self.reference_version
return obj

def clone(self, map_inst=None):
new = self.__class__.objects.get(pk=self.pk)
new._state.adding = True
new.pk = None
new.pk = uuid.uuid4()
if map_inst:
new.map = map_inst
new.geojson = File(new.geojson.file.file)
Expand All @@ -543,11 +542,20 @@ def is_valid_version(self, name):
valid_prefixes.append(name.startswith("%s_" % self.old_id))
return any(valid_prefixes) and name.endswith(".geojson")

def extract_version_number(self, path):
version = path.split(".")[0]
if "_" in version:
return version.split("_")[-1]
return version

@property
def reference_version(self):
return self.extract_version_number(self.geojson.path)

def version_metadata(self, name):
els = name.split(".")[0].split("_")
return {
"name": name,
"at": els[1],
"at": self.extract_version_number(name),
"size": self.geojson.storage.size(self.get_version_path(name)),
}

Expand Down
2 changes: 1 addition & 1 deletion umap/static/umap/js/modules/data/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class Feature {
subject: 'feature',
metadata: {
id: this.id,
layerId: this.datalayer?.umap_id || null,
layerId: this.datalayer.id,
featureType: this.getClassName(),
},
}
Expand Down
96 changes: 54 additions & 42 deletions umap/static/umap/js/modules/data/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const LAYER_MAP = LAYER_TYPES.reduce((acc, klass) => {
}, {})

export class DataLayer extends ServerStored {
constructor(umap, leafletMap, data) {
constructor(umap, leafletMap, data = {}) {
super()
this._umap = umap
this.sync = umap.sync_engine.proxy(this)
Expand All @@ -51,10 +51,7 @@ export class DataLayer extends ServerStored {

this._leafletMap = leafletMap
this.parentPane = this._leafletMap.getPane('overlayPane')
this.pane = this._leafletMap.createPane(
`datalayer${stamp(this)}`,
this.parentPane
)
this.pane = this._leafletMap.createPane(`datalayer${stamp(this)}`, this.parentPane)
this.pane.dataset.id = stamp(this)
// FIXME: should be on layer
this.renderer = L.svg({ pane: this.pane })
Expand All @@ -66,7 +63,11 @@ export class DataLayer extends ServerStored {
}

this._isDeleted = false
this.setUmapId(data.id)
this._referenceVersion = data._referenceVersion
// Do not save it later.
delete data._referenceVersion
data.id = data.id || crypto.randomUUID()

this.setOptions(data)

if (!Utils.isObject(this.options.remoteData)) {
Expand All @@ -84,7 +85,8 @@ export class DataLayer extends ServerStored {
this.backupOptions()
this.connectToMap()
this.permissions = new DataLayerPermissions(this._umap, this)
if (!this.umap_id) {

if (!this.createdOnServer) {
if (this.showAtLoad()) this.show()
this.isDirty = true
}
Expand All @@ -95,6 +97,14 @@ export class DataLayer extends ServerStored {
if (this.isVisible()) this.propagateShow()
}

get id() {
return this.options.id
}

get createdOnServer() {
return Boolean(this._referenceVersion)
}

onDirty(status) {
if (status) {
// A layer can be made dirty by indirect action (like dragging layers)
Expand All @@ -121,9 +131,7 @@ export class DataLayer extends ServerStored {
getSyncMetadata() {
return {
subject: 'datalayer',
metadata: {
id: this.umap_id || null,
},
metadata: { id: this.id },
}
}

Expand Down Expand Up @@ -160,7 +168,7 @@ export class DataLayer extends ServerStored {
autoLoaded() {
if (!this._umap.datalayersFromQueryString) return this.options.displayOnLoad
const datalayerIds = this._umap.datalayersFromQueryString
let loadMe = datalayerIds.includes(this.umap_id.toString())
let loadMe = datalayerIds.includes(this.id.toString())
if (this.options.old_id) {
loadMe = loadMe || datalayerIds.includes(this.options.old_id.toString())
}
Expand Down Expand Up @@ -215,13 +223,13 @@ export class DataLayer extends ServerStored {
}

async fetchData() {
if (!this.umap_id) return
if (!this.createdOnServer) return
if (this._loading) return
this._loading = true
const [geojson, response, error] = await this._umap.server.get(this._dataUrl())
if (!error) {
this._reference_version = response.headers.get('X-Datalayer-Version')
// FIXME: for now this property is set dynamically from backend
this.setReferenceVersion({ response, sync: false })
// FIXME: for now the _umap_options property is set dynamically from backend
// And thus it's not in the geojson file in the server
// So do not let all options to be reset
// Fix is a proper migration so all datalayers settings are
Expand Down Expand Up @@ -257,6 +265,7 @@ export class DataLayer extends ServerStored {

async fromUmapGeoJSON(geojson) {
if (geojson._storage) geojson._umap_options = geojson._storage // Retrocompat
geojson._umap_options.id = this.id
if (geojson._umap_options) this.setOptions(geojson._umap_options)
if (this.isRemoteLayer()) await this.fetchRemoteData()
else this.fromGeoJSON(geojson, false)
Expand Down Expand Up @@ -313,18 +322,13 @@ export class DataLayer extends ServerStored {
}

isLoaded() {
return !this.umap_id || this._loaded
return !this.createdOnServer || this._loaded
}

hasDataLoaded() {
return this._dataloaded
}

setUmapId(id) {
// Datalayer is null when listening creation form
if (!this.umap_id && id) this.umap_id = id
}

backupOptions() {
this._backupOptions = Utils.CopyJSON(this.options)
}
Expand Down Expand Up @@ -357,8 +361,8 @@ export class DataLayer extends ServerStored {

_dataUrl() {
let url = this._umap.urls.get('datalayer_view', {
pk: this.umap_id,
map_id: this._umap.properties.umap_id,
pk: this.id,
map_id: this._umap.id,
})

// No browser cache for owners/editors.
Expand Down Expand Up @@ -437,7 +441,7 @@ export class DataLayer extends ServerStored {
// otherwise the layer becomes uneditable.
this.makeFeatures(geojson, sync)
} catch (err) {
console.log('Error with DataLayer', this.umap_id)
console.log('Error with DataLayer', this.id)
console.error(err)
}
}
Expand Down Expand Up @@ -524,22 +528,22 @@ export class DataLayer extends ServerStored {

getDeleteUrl() {
return this._umap.urls.get('datalayer_delete', {
pk: this.umap_id,
map_id: this._umap.properties.umap_id,
pk: this.id,
map_id: this._umap.id,
})
}

getVersionsUrl() {
return this._umap.urls.get('datalayer_versions', {
pk: this.umap_id,
map_id: this._umap.properties.umap_id,
pk: this.id,
map_id: this._umap.id,
})
}

getVersionUrl(name) {
return this._umap.urls.get('datalayer_version', {
pk: this.umap_id,
map_id: this._umap.properties.umap_id,
pk: this.id,
map_id: this._umap.id,
name: name,
})
}
Expand Down Expand Up @@ -579,7 +583,8 @@ export class DataLayer extends ServerStored {
}

reset() {
if (!this.umap_id) this.erase()
if (!this.createdOnServer) this.erase()

this.resetOptions()
this.parentPane.appendChild(this.pane)
if (this._leaflet_events_bk && !this._leaflet_events) {
Expand Down Expand Up @@ -809,7 +814,7 @@ export class DataLayer extends ServerStored {
},
this
)
if (this.umap_id) {
if (this.createdOnServer) {
const filename = `${Utils.slugify(this.options.name)}.geojson`
const download = Utils.loadTemplate(`
<a class="button" href="${this._dataUrl()}" download="${filename}">
Expand Down Expand Up @@ -1034,6 +1039,11 @@ export class DataLayer extends ServerStored {
return this.isReadOnly() || this.isRemoteLayer()
}

setReferenceVersion({ response, sync }) {
this._referenceVersion = response.headers.get('X-Datalayer-Version')
this.sync.update('_referenceVersion', this._referenceVersion)
}

async save() {
if (this.isDeleted) return await this.saveDelete()
if (!this.isLoaded()) {
Expand All @@ -1048,14 +1058,15 @@ export class DataLayer extends ServerStored {
// Filename support is shaky, don't do it for now.
const blob = new Blob([JSON.stringify(geojson)], { type: 'application/json' })
formData.append('geojson', blob)
const saveUrl = this._umap.urls.get('datalayer_save', {
map_id: this._umap.properties.umap_id,
pk: this.umap_id,
const saveURL = this._umap.urls.get('datalayer_save', {
map_id: this._umap.id,
pk: this.id,
created: this.createdOnServer,
})
const headers = this._reference_version
? { 'X-Datalayer-Reference': this._reference_version }
const headers = this._referenceVersion
? { 'X-Datalayer-Reference': this._referenceVersion }
: {}
const status = await this._trySave(saveUrl, headers, formData)
const status = await this._trySave(saveURL, headers, formData)
this._geojson = geojson
return status
}
Expand Down Expand Up @@ -1090,11 +1101,12 @@ export class DataLayer extends ServerStored {
this.fromGeoJSON(data.geojson)
delete data.geojson
}
this._reference_version = response.headers.get('X-Datalayer-Version')
this.sync.update('_reference_version', this._reference_version)

this.setUmapId(data.id)
delete data.id
delete data._referenceVersion
this.updateOptions(data)

this.setReferenceVersion({ response, sync: true })

this.backupOptions()
this.backupData()
this.connectToMap()
Expand All @@ -1105,7 +1117,7 @@ export class DataLayer extends ServerStored {
}

async saveDelete() {
if (this.umap_id) {
if (this.createdOnServer) {
await this._umap.server.post(this.getDeleteUrl())
}
delete this._umap.datalayers[stamp(this)]
Expand Down
10 changes: 5 additions & 5 deletions umap/static/umap/js/modules/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class MapPermissions extends ServerStored {

edit() {
if (this._umap.properties.editMode !== 'advanced') return
if (!this._umap.properties.umap_id) {
if (!this._umap.id) {
Alert.info(translate('Please save the map first'))
return
}
Expand Down Expand Up @@ -199,13 +199,13 @@ export class MapPermissions extends ServerStored {

getUrl() {
return this._umap.urls.get('map_update_permissions', {
map_id: this._umap.properties.umap_id,
map_id: this._umap.id,
})
}

getAttachUrl() {
return this._umap.urls.get('map_attach_owner', {
map_id: this._umap.properties.umap_id,
map_id: this._umap.id,
})
}

Expand Down Expand Up @@ -262,8 +262,8 @@ export class DataLayerPermissions extends ServerStored {

getUrl() {
return this._umap.urls.get('datalayer_permissions', {
map_id: this._umap.properties.umap_id,
pk: this.datalayer.umap_id,
map_id: this._umap.id,
pk: this.datalayer.id,
})
}

Expand Down
5 changes: 5 additions & 0 deletions umap/static/umap/js/modules/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,4 +563,9 @@ export const SCHEMA = {
type: Object,
impacts: ['data'],
},

_referenceVersion: {
type: Number,
impacts: ['data'],
},
}
Loading

0 comments on commit 8105376

Please sign in to comment.