mirror of
https://github.com/umap-project/umap.git
synced 2025-05-11 00:21:49 +02:00
Compare commits
No commits in common. "45a0ec5d428c8985a241dd3d668a52677b597d94" and "dd89984e28f981db167026c9294d3a5c9d6bc46c" have entirely different histories.
45a0ec5d42
...
dd89984e28
11 changed files with 71 additions and 157 deletions
|
@ -1,11 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 2.8.0a2 - 2024-12-13
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
* make sure we set X-DataLayer-Version even when using X-Accel-Redirect by @yohanboniface in #2361
|
|
||||||
* refactor importer feedback by @yohanboniface in #2363
|
|
||||||
|
|
||||||
## 2.8.0a1 - 2024-12-11
|
## 2.8.0a1 - 2024-12-11
|
||||||
|
|
||||||
### Internal changes
|
### Internal changes
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
VERSION = "2.8.0a2"
|
VERSION = "2.8.0a1"
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-12-13 08:26+0000\n"
|
"POT-Creation-Date: 2024-12-11 17:05+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -617,57 +617,57 @@ msgstr ""
|
||||||
msgid "View the map"
|
msgid "View the map"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:821
|
#: views.py:820
|
||||||
msgid "See full screen"
|
msgid "See full screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:964
|
#: views.py:963
|
||||||
msgid "Map editors updated with success!"
|
msgid "Map editors updated with success!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1000
|
#: views.py:999
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The uMap edit link for your map: %(map_name)s"
|
msgid "The uMap edit link for your map: %(map_name)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1003
|
#: views.py:1002
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Here is your secret edit link: %(link)s"
|
msgid "Here is your secret edit link: %(link)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1010
|
#: views.py:1009
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Can't send email to %(email)s"
|
msgid "Can't send email to %(email)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1013
|
#: views.py:1012
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Email sent to %(email)s"
|
msgid "Email sent to %(email)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1024
|
#: views.py:1023
|
||||||
msgid "Only its owner can delete the map."
|
msgid "Only its owner can delete the map."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1027
|
#: views.py:1026
|
||||||
msgid "Map successfully deleted."
|
msgid "Map successfully deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1053
|
#: views.py:1052
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your map has been cloned! If you want to edit this map from another "
|
"Your map has been cloned! If you want to edit this map from another "
|
||||||
"computer, please use this link: %(anonymous_url)s"
|
"computer, please use this link: %(anonymous_url)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1058
|
#: views.py:1057
|
||||||
msgid "Congratulations, your map has been cloned!"
|
msgid "Congratulations, your map has been cloned!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1309
|
#: views.py:1308
|
||||||
msgid "Layer successfully deleted."
|
msgid "Layer successfully deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: views.py:1331
|
#: views.py:1330
|
||||||
msgid "Permissions updated with success!"
|
msgid "Permissions updated with success!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -252,11 +252,10 @@ export class DataLayer extends ServerStored {
|
||||||
}
|
}
|
||||||
|
|
||||||
fromGeoJSON(geojson, sync = true) {
|
fromGeoJSON(geojson, sync = true) {
|
||||||
const features = this.addData(geojson, sync)
|
this.addData(geojson, sync)
|
||||||
this._geojson = geojson
|
this._geojson = geojson
|
||||||
this.onDataLoaded()
|
this.onDataLoaded()
|
||||||
this.dataChanged()
|
this.dataChanged()
|
||||||
return features
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDataLoaded() {
|
onDataLoaded() {
|
||||||
|
@ -316,7 +315,7 @@ export class DataLayer extends ServerStored {
|
||||||
const response = await this._umap.request.get(url)
|
const response = await this._umap.request.get(url)
|
||||||
if (response?.ok) {
|
if (response?.ok) {
|
||||||
this.clear()
|
this.clear()
|
||||||
return this._umap.formatter
|
this._umap.formatter
|
||||||
.parse(await response.text(), this.options.remoteData.format)
|
.parse(await response.text(), this.options.remoteData.format)
|
||||||
.then((geojson) => this.fromGeoJSON(geojson))
|
.then((geojson) => this.fromGeoJSON(geojson))
|
||||||
}
|
}
|
||||||
|
@ -444,11 +443,10 @@ export class DataLayer extends ServerStored {
|
||||||
try {
|
try {
|
||||||
// Do not fail if remote data is somehow invalid,
|
// Do not fail if remote data is somehow invalid,
|
||||||
// otherwise the layer becomes uneditable.
|
// otherwise the layer becomes uneditable.
|
||||||
return this.makeFeatures(geojson, sync)
|
this.makeFeatures(geojson, sync)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Error with DataLayer', this.id)
|
console.log('Error with DataLayer', this.id)
|
||||||
console.error(err)
|
console.error(err)
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,13 +463,10 @@ export class DataLayer extends ServerStored {
|
||||||
? geojson
|
? geojson
|
||||||
: geojson.features || geojson.geometries
|
: geojson.features || geojson.geometries
|
||||||
if (!collection) return
|
if (!collection) return
|
||||||
const features = []
|
|
||||||
this.sortFeatures(collection)
|
this.sortFeatures(collection)
|
||||||
for (const featureJson of collection) {
|
for (const feature of collection) {
|
||||||
const feature = this.makeFeature(featureJson, sync)
|
this.makeFeature(feature, sync)
|
||||||
if (feature) features.push(feature)
|
|
||||||
}
|
}
|
||||||
return features
|
|
||||||
}
|
}
|
||||||
|
|
||||||
makeFeature(geojson = {}, sync = true, id = null) {
|
makeFeature(geojson = {}, sync = true, id = null) {
|
||||||
|
@ -508,47 +503,31 @@ export class DataLayer extends ServerStored {
|
||||||
}
|
}
|
||||||
|
|
||||||
async importRaw(raw, format) {
|
async importRaw(raw, format) {
|
||||||
return this._umap.formatter
|
this._umap.formatter
|
||||||
.parse(raw, format)
|
.parse(raw, format)
|
||||||
.then((geojson) => this.addData(geojson))
|
.then((geojson) => this.addData(geojson))
|
||||||
.then((data) => {
|
.then(() => this.zoomTo())
|
||||||
if (data?.length) this.isDirty = true
|
this.isDirty = true
|
||||||
return data
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readFile(f) {
|
importFromFiles(files, type) {
|
||||||
return new Promise((resolve) => {
|
for (const f of files) {
|
||||||
const reader = new FileReader()
|
this.importFromFile(f, type)
|
||||||
reader.onloadend = () => resolve(reader.result)
|
|
||||||
reader.readAsText(f)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async importFromFiles(files, type) {
|
|
||||||
let all = []
|
|
||||||
for (const file of files) {
|
|
||||||
const features = await this.importFromFile(file, type)
|
|
||||||
if (features) {
|
|
||||||
all = all.concat(features)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new Promise((resolve) => {
|
|
||||||
resolve(all)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async importFromFile(file, type) {
|
importFromFile(f, type) {
|
||||||
|
const reader = new FileReader()
|
||||||
type = type || Utils.detectFileType(f)
|
type = type || Utils.detectFileType(f)
|
||||||
const raw = await this.readFile(file)
|
reader.readAsText(f)
|
||||||
return this.importRaw(raw, type)
|
reader.onload = (e) => this.importRaw(e.target.result, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
async importFromUrl(uri, type) {
|
async importFromUrl(uri, type) {
|
||||||
uri = this._umap.renderUrl(uri)
|
uri = this._umap.renderUrl(uri)
|
||||||
const response = await this._umap.request.get(uri)
|
const response = await this._umap.request.get(uri)
|
||||||
if (response?.ok) {
|
if (response?.ok) {
|
||||||
return this.importRaw(await response.text(), type)
|
this.importRaw(await response.text(), type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,9 +930,9 @@ export class DataLayer extends ServerStored {
|
||||||
else this.hide()
|
else this.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomTo(bounds) {
|
zoomTo() {
|
||||||
if (!this.isVisible()) return
|
if (!this.isVisible()) return
|
||||||
bounds = bounds || this.layer.getBounds()
|
const bounds = this.layer.getBounds()
|
||||||
if (bounds.isValid()) {
|
if (bounds.isValid()) {
|
||||||
const options = { maxZoom: this.getOption('zoomTo') }
|
const options = { maxZoom: this.getOption('zoomTo') }
|
||||||
this._leafletMap.fitBounds(bounds, options)
|
this._leafletMap.fitBounds(bounds, options)
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import {
|
import { DomEvent, DomUtil } from '../../vendors/leaflet/leaflet-src.esm.js'
|
||||||
DomEvent,
|
|
||||||
DomUtil,
|
|
||||||
LatLngBounds,
|
|
||||||
} from '../../vendors/leaflet/leaflet-src.esm.js'
|
|
||||||
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
import { uMapAlert as Alert } from '../components/alerts/alert.js'
|
||||||
import { translate } from './i18n.js'
|
import { translate } from './i18n.js'
|
||||||
import { SCHEMA } from './schema.js'
|
import { SCHEMA } from './schema.js'
|
||||||
|
@ -274,12 +270,16 @@ export default class Importer extends Utils.WithTemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
submit() {
|
||||||
|
let hasErrors
|
||||||
if (this.format === 'umap') {
|
if (this.format === 'umap') {
|
||||||
this.full()
|
hasErrors = !this.full()
|
||||||
} else if (!this.url) {
|
} else if (!this.url) {
|
||||||
this.copy()
|
hasErrors = !this.copy()
|
||||||
} else if (this.action) {
|
} else if (this.action) {
|
||||||
this[this.action]()
|
hasErrors = !this[this.action]()
|
||||||
|
}
|
||||||
|
if (hasErrors === false) {
|
||||||
|
Alert.info(translate('Data successfully imported!'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,9 +294,8 @@ export default class Importer extends Utils.WithTemplate {
|
||||||
} else if (this.url) {
|
} else if (this.url) {
|
||||||
this._umap.importFromUrl(this.url, this.format)
|
this._umap.importFromUrl(this.url, this.format)
|
||||||
}
|
}
|
||||||
this.onSuccess()
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.onError(translate('Invalid umap data'))
|
Alert.error(translate('Invalid umap data'))
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -307,7 +306,7 @@ export default class Importer extends Utils.WithTemplate {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!this.format) {
|
if (!this.format) {
|
||||||
this.onError(translate('Please choose a format'))
|
Alert.error(translate('Please choose a format'))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const layer = this.layer
|
const layer = this.layer
|
||||||
|
@ -319,67 +318,26 @@ export default class Importer extends Utils.WithTemplate {
|
||||||
layer.options.remoteData.proxy = true
|
layer.options.remoteData.proxy = true
|
||||||
layer.options.remoteData.ttl = SCHEMA.ttl.default
|
layer.options.remoteData.ttl = SCHEMA.ttl.default
|
||||||
}
|
}
|
||||||
layer.fetchRemoteData(true).then((features) => {
|
layer.fetchRemoteData(true)
|
||||||
if (features?.length) {
|
|
||||||
layer.zoomTo()
|
|
||||||
this.onSuccess()
|
|
||||||
} else {
|
|
||||||
this.onError()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async copy() {
|
copy() {
|
||||||
// Format may be guessed from file later.
|
// Format may be guessed from file later.
|
||||||
// Usefull in case of multiple files with different formats.
|
// Usefull in case of multiple files with different formats.
|
||||||
if (!this.format && !this.files.length) {
|
if (!this.format && !this.files.length) {
|
||||||
this.onError(translate('Please choose a format'))
|
Alert.error(translate('Please choose a format'))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let promise
|
|
||||||
const layer = this.layer
|
const layer = this.layer
|
||||||
if (this.clear) layer.empty()
|
if (this.clear) layer.empty()
|
||||||
if (this.files.length) {
|
if (this.files.length) {
|
||||||
promise = layer.importFromFiles(this.files, this.format)
|
for (const file of this.files) {
|
||||||
} else if (this.raw) {
|
this._umap.processFileToImport(file, layer, this.format)
|
||||||
promise = layer.importRaw(this.raw, this.format)
|
|
||||||
} else if (this.url) {
|
|
||||||
promise = layer.importFromUrl(this.url, this.format)
|
|
||||||
}
|
|
||||||
if (promise) promise.then((data) => this.onCopyFinished(layer, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
onError(message = translate('No data has been found for import')) {
|
|
||||||
Alert.error(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuccess(count) {
|
|
||||||
if (count) {
|
|
||||||
Alert.success(
|
|
||||||
translate('Successfully imported {count} feature(s)', {
|
|
||||||
count: count,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Alert.success(translate('Data successfully imported!'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onCopyFinished(layer, features) {
|
|
||||||
// undefined features means error, let original error message pop
|
|
||||||
if (!features) return
|
|
||||||
if (!features.length) {
|
|
||||||
this.onError()
|
|
||||||
} else {
|
|
||||||
const bounds = new LatLngBounds()
|
|
||||||
for (const feature of features) {
|
|
||||||
const featureBounds = feature.ui.getBounds
|
|
||||||
? feature.ui.getBounds()
|
|
||||||
: feature.ui.getCenter()
|
|
||||||
bounds.extend(featureBounds)
|
|
||||||
}
|
}
|
||||||
this.onSuccess(features.length)
|
} else if (this.raw) {
|
||||||
layer.zoomTo(bounds)
|
layer.importRaw(this.raw, this.format)
|
||||||
|
} else if (this.url) {
|
||||||
|
layer.importFromUrl(this.url, this.format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,14 +316,12 @@ export default class Umap extends ServerStored {
|
||||||
dataUrl = this.renderUrl(dataUrl)
|
dataUrl = this.renderUrl(dataUrl)
|
||||||
dataUrl = this.proxyUrl(dataUrl)
|
dataUrl = this.proxyUrl(dataUrl)
|
||||||
const datalayer = this.createDataLayer()
|
const datalayer = this.createDataLayer()
|
||||||
await datalayer
|
await datalayer.importFromUrl(dataUrl, dataFormat)
|
||||||
.importFromUrl(dataUrl, dataFormat)
|
|
||||||
.then(() => datalayer.zoomTo())
|
|
||||||
}
|
}
|
||||||
} else if (data) {
|
} else if (data) {
|
||||||
data = decodeURIComponent(data)
|
data = decodeURIComponent(data)
|
||||||
const datalayer = this.createDataLayer()
|
const datalayer = this.createDataLayer()
|
||||||
await datalayer.importRaw(data, dataFormat).then(() => datalayer.zoomTo())
|
await datalayer.importRaw(data, dataFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,12 +641,6 @@ export default class Umap extends ServerStored {
|
||||||
// have changed, we'll be more subtil when we'll remove the
|
// have changed, we'll be more subtil when we'll remove the
|
||||||
// save action
|
// save action
|
||||||
this.render(['name', 'user', 'permissions'])
|
this.render(['name', 'user', 'permissions'])
|
||||||
if (!this._leafletMap.listens('saved')) {
|
|
||||||
// When we save only layers, we don't have the map feedback message
|
|
||||||
this._leafletMap.on('saved', () => {
|
|
||||||
Alert.success(translate('Map has been saved!'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.fire('saved')
|
this.fire('saved')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1522,7 +1514,7 @@ export default class Umap extends ServerStored {
|
||||||
processFileToImport(file, layer, type) {
|
processFileToImport(file, layer, type) {
|
||||||
type = type || Utils.detectFileType(file)
|
type = type || Utils.detectFileType(file)
|
||||||
if (!type) {
|
if (!type) {
|
||||||
Alert.error(
|
U.Alert.error(
|
||||||
translate('Unable to detect format of file {filename}', {
|
translate('Unable to detect format of file {filename}', {
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
})
|
})
|
||||||
|
|
|
@ -520,9 +520,7 @@ const locale = {
|
||||||
"Import helpers": "Import helpers",
|
"Import helpers": "Import helpers",
|
||||||
"Import helpers will fill the URL field for you.": "Import helpers will fill the URL field for you.",
|
"Import helpers will fill the URL field for you.": "Import helpers will fill the URL field for you.",
|
||||||
"Wikipedia": "Wikipedia",
|
"Wikipedia": "Wikipedia",
|
||||||
"Save draft": "Save draft",
|
"Save draft": "Save draft"
|
||||||
"No data has been found for import": "No data has been found for import",
|
|
||||||
"Successfully imported {count} feature(s)": "Successfully imported {count} feature(s)"
|
|
||||||
}
|
}
|
||||||
L.registerLocale("en", locale)
|
L.registerLocale("en", locale)
|
||||||
L.setLocale("en")
|
L.setLocale("en")
|
||||||
|
|
|
@ -520,7 +520,5 @@
|
||||||
"Import helpers": "Import helpers",
|
"Import helpers": "Import helpers",
|
||||||
"Import helpers will fill the URL field for you.": "Import helpers will fill the URL field for you.",
|
"Import helpers will fill the URL field for you.": "Import helpers will fill the URL field for you.",
|
||||||
"Wikipedia": "Wikipedia",
|
"Wikipedia": "Wikipedia",
|
||||||
"Save draft": "Save draft",
|
"Save draft": "Save draft"
|
||||||
"No data has been found for import": "No data has been found for import",
|
|
||||||
"Successfully imported {count} feature(s)": "Successfully imported {count} feature(s)"
|
|
||||||
}
|
}
|
|
@ -520,9 +520,7 @@ const locale = {
|
||||||
"Import helpers": "Assistants d'import",
|
"Import helpers": "Assistants d'import",
|
||||||
"Import helpers will fill the URL field for you.": "Les assistants d'import vont renseigner le champ URL pour vous.",
|
"Import helpers will fill the URL field for you.": "Les assistants d'import vont renseigner le champ URL pour vous.",
|
||||||
"Wikipedia": "Wikipedia",
|
"Wikipedia": "Wikipedia",
|
||||||
"Save draft": "Enregistrer le brouillon",
|
"Save draft": "Enregistrer le brouillon"
|
||||||
"No data has been found for import": "Aucunes données à importer",
|
|
||||||
"Successfully imported {count} feature(s)": "{count} élément(s) ajouté(s) à la carte"
|
|
||||||
}
|
}
|
||||||
L.registerLocale("fr", locale)
|
L.registerLocale("fr", locale)
|
||||||
L.setLocale("fr")
|
L.setLocale("fr")
|
||||||
|
|
|
@ -520,7 +520,5 @@
|
||||||
"Import helpers": "Assistants d'import",
|
"Import helpers": "Assistants d'import",
|
||||||
"Import helpers will fill the URL field for you.": "Les assistants d'import vont renseigner le champ URL pour vous.",
|
"Import helpers will fill the URL field for you.": "Les assistants d'import vont renseigner le champ URL pour vous.",
|
||||||
"Wikipedia": "Wikipedia",
|
"Wikipedia": "Wikipedia",
|
||||||
"Save draft": "Enregistrer le brouillon",
|
"Save draft": "Enregistrer le brouillon"
|
||||||
"No data has been found for import": "Aucunes données à importer",
|
|
||||||
"Successfully imported {count} feature(s)": "{count} élément(s) ajouté(s) à la carte"
|
|
||||||
}
|
}
|
|
@ -452,27 +452,27 @@ showcase = MapsShowCase.as_view()
|
||||||
|
|
||||||
|
|
||||||
def validate_url(request):
|
def validate_url(request):
|
||||||
assert request.method == "GET", "Wrong HTTP method"
|
assert request.method == "GET"
|
||||||
url = request.GET.get("url")
|
url = request.GET.get("url")
|
||||||
assert url, "Missing URL"
|
assert url
|
||||||
try:
|
try:
|
||||||
URLValidator(url)
|
URLValidator(url)
|
||||||
except ValidationError as err:
|
except ValidationError:
|
||||||
raise AssertionError(err)
|
raise AssertionError()
|
||||||
assert "HTTP_REFERER" in request.META, "Missing HTTP_REFERER"
|
assert "HTTP_REFERER" in request.META
|
||||||
referer = urlparse(request.META.get("HTTP_REFERER"))
|
referer = urlparse(request.META.get("HTTP_REFERER"))
|
||||||
toproxy = urlparse(url)
|
toproxy = urlparse(url)
|
||||||
local = urlparse(settings.SITE_URL)
|
local = urlparse(settings.SITE_URL)
|
||||||
assert toproxy.hostname, "No hostname"
|
assert toproxy.hostname
|
||||||
assert referer.hostname == local.hostname, f"{referer.hostname} != {local.hostname}"
|
assert referer.hostname == local.hostname
|
||||||
assert toproxy.hostname != "localhost", "Invalid localhost target"
|
assert toproxy.hostname != "localhost"
|
||||||
assert toproxy.netloc != local.netloc, "Invalid netloc"
|
assert toproxy.netloc != local.netloc
|
||||||
try:
|
try:
|
||||||
# clean this when in python 3.4
|
# clean this when in python 3.4
|
||||||
ipaddress = socket.gethostbyname(toproxy.hostname)
|
ipaddress = socket.gethostbyname(toproxy.hostname)
|
||||||
except Exception as err:
|
except:
|
||||||
raise AssertionError(err)
|
raise AssertionError()
|
||||||
assert not PRIVATE_IP.match(ipaddress), "Private IP"
|
assert not PRIVATE_IP.match(ipaddress)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
@ -480,8 +480,7 @@ class AjaxProxy(View):
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
url = validate_url(self.request)
|
url = validate_url(self.request)
|
||||||
except AssertionError as err:
|
except AssertionError:
|
||||||
print(f"AjaxProxy: {err}")
|
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
try:
|
try:
|
||||||
ttl = int(self.request.GET.get("ttl"))
|
ttl = int(self.request.GET.get("ttl"))
|
||||||
|
|
Loading…
Reference in a new issue