Move permissions form building to JS

This commit is contained in:
Yohan Boniface 2018-06-15 23:25:38 +02:00
parent 6b3d45064c
commit 48185650b0
18 changed files with 368 additions and 156 deletions

View file

@ -1,4 +1,5 @@
Django==2.0.5
django-agnocomplete==0.12.2
django-compressor==2.1.1
Pillow==5.1.0
psycopg2==2.7.4

19
umap/autocomplete.py Normal file
View file

@ -0,0 +1,19 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.urls import reverse
from agnocomplete.register import register
from agnocomplete.core import AgnocompleteModel
@register
class AutocompleteUser(AgnocompleteModel):
model = get_user_model()
fields = ['^username']
def item(self, current_item):
data = super().item(current_item)
data['url'] = reverse(settings.USER_MAPS_URL,
args=(current_item.get_username(), ))
return data

View file

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
from django import forms
from django.contrib.gis.geos import Point
from django.contrib.auth import get_user_model
@ -28,7 +26,6 @@ class FlatErrorList(ErrorList):
class UpdateMapPermissionsForm(forms.ModelForm):
owner = forms.ModelChoiceField(User.objects, required=True)
class Meta:
model = Map

View file

@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
import os
import time
@ -175,6 +173,8 @@ class Map(NamedModel):
and self.is_anonymous_owner(request)):
can = True
if user and user.is_authenticated:
# TODO: only when using the anonymous-edit URL with an
# authenticated user
# if user is authenticated, attach as owner
self.owner = user
self.save()

View file

@ -78,6 +78,7 @@ INSTALLED_APPS = (
'umap',
'compressor',
'social_django',
'agnocomplete',
)
# =============================================================================
@ -159,8 +160,6 @@ MIDDLEWARE = (
# =============================================================================
ENABLE_ACCOUNT_LOGIN = False
AUTHENTICATION_BACKENDS += (
)
# =============================================================================
# Miscellaneous project settings

View file

@ -12,8 +12,10 @@ L.U.AutoComplete = L.Class.extend({
RESULTS: [],
initialize: function (el, options) {
this.el = L.DomUtil.get(el);
L.setOptions(options);
this.el = el;
var ui = new L.U.UI(document.querySelector('header'));
this.xhr = new L.U.Xhr(ui);
L.setOptions(this, options);
var CURRENT = null;
try {
Object.defineProperty(this, 'CURRENT', {
@ -37,9 +39,9 @@ L.U.AutoComplete = L.Class.extend({
this.input = L.DomUtil.element('input', {
type: 'text',
placeholder: this.options.placeholder,
autocomplete: 'off'
});
L.DomUtil.before(this.el, this.input);
autocomplete: 'off',
className: this.options.className
}, this.el);
L.DomEvent.on(this.input, 'keydown', this.onKeyDown, this);
L.DomEvent.on(this.input, 'keyup', this.onKeyUp, this);
L.DomEvent.on(this.input, 'blur', this.onBlur, this);
@ -63,10 +65,7 @@ L.U.AutoComplete = L.Class.extend({
onKeyDown: function (e) {
switch (e.keyCode) {
case L.U.Keys.TAB:
if(this.CURRENT !== null)
{
this.setChoice();
}
if(this.CURRENT !== null) this.setChoice();
L.DomEvent.stop(e);
break;
case L.U.Keys.ENTER:
@ -149,8 +148,8 @@ L.U.AutoComplete = L.Class.extend({
setChoice: function (choice) {
choice = choice || this.RESULTS[this.CURRENT];
if (choice) {
this.input.value = choice.display;
this.select(choice);
this.input.value = choice.item.label;
this.options.on_select(choice);
this.displaySelected(choice);
this.hide();
if (this.options.callback) {
@ -165,26 +164,18 @@ L.U.AutoComplete = L.Class.extend({
this.clear();
return;
}
if(!val) {
this.clear();
return;
}
if( val + '' === this.CACHE + '') {
return;
}
else {
this.CACHE = val;
}
var results = this._do_search(val);
return this.handleResults(results);
if( val + '' === this.CACHE + '') return;
else this.CACHE = val;
this._do_search(val, (data) => {
this.handleResults(data.data);
});
},
createResult: function (item) {
var el = L.DomUtil.element('li', {}, this.container);
el.innerHTML = item.display;
el.innerHTML = item.label;
var result = {
value: item.value,
display: item.display,
item: item,
el: el
};
L.DomEvent.on(el, 'mouseover', function () {
@ -223,12 +214,12 @@ L.U.AutoComplete = L.Class.extend({
highlight: function () {
var self = this;
this.forEach(this.RESULTS, function (item, index) {
this.forEach(this.RESULTS, function (result, index) {
if (index === self.CURRENT) {
L.DomUtil.addClass(item.el, 'on');
L.DomUtil.addClass(result.el, 'on');
}
else {
L.DomUtil.removeClass(item.el, 'on');
L.DomUtil.removeClass(result.el, 'on');
}
});
},
@ -260,114 +251,69 @@ L.U.AutoComplete = L.Class.extend({
});
L.U.AutoComplete.BaseSelect = L.U.AutoComplete.extend({
L.U.AutoComplete.Ajax = L.U.AutoComplete.extend({
initialize: function (el, options) {
L.U.AutoComplete.prototype.initialize.call(this, el, options);
if (!this.el) return this;
this.el.style.display = 'none';
this.createInput();
this.createContainer();
this.initSelectedContainer();
this.selected_container = this.initSelectedContainer();
},
optionToResult: function (option) {
return {
value: option.value,
display: option.innerHTML
label: option.innerHTML
};
},
_do_search: function (val) {
var results = [],
self = this,
count = 0;
val = val.toLowerCase();
this.forEach(this.el, function (item) {
var candidate = item.innerHTML.toLowerCase();
if (candidate === val || (candidate.indexOf(val) !== -1 && !item.selected && count < self.options.maxResults)) {
results.push(self.optionToResult(item));
count++;
}
});
return results;
},
select: function (option) {
this.forEach(this.el, function (item) {
if (item.value == option.value) {
item.selected = true;
}
});
},
unselect: function (option) {
this.forEach(this.el, function (item) {
if (item.value == option.value) {
item.selected = false;
}
});
_do_search: function (val, callback) {
val = val.toLowerCase();
this.xhr.get('/agnocomplete/AutocompleteUser/?q=' + encodeURIComponent(val), {callback: callback});
}
});
L.U.AutoComplete.MultiSelect = L.U.AutoComplete.BaseSelect.extend({
L.U.AutoComplete.Ajax.SelectMultiple = L.U.AutoComplete.Ajax.extend({
initSelectedContainer: function () {
this.selected_container = L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'}));
var self = this;
this.forEach(this.el, function (option) {
if (option.selected) {
self.displaySelected(self.optionToResult(option));
}
});
return L.DomUtil.after(this.input, L.DomUtil.element('ul', {className: 'umap-multiresult'}));
},
displaySelected: function (result) {
var result_el = L.DomUtil.element('li', {}, this.selected_container);
result_el.innerHTML = result.display;
result_el.innerHTML = result.item.label;
var close = L.DomUtil.element('span', {className: 'close'}, result_el);
close.innerHTML = '×';
L.DomEvent.on(close, 'click', function () {
this.selected_container.removeChild(result_el);
this.unselect(result);
this.options.on_unselect(result);
}, this);
this.hide();
}
});
L.U.AutoComplete.multiSelect = function (el, options) {
return new L.U.AutoComplete.MultiSelect(el, options);
};
L.U.AutoComplete.Select = L.U.AutoComplete.BaseSelect.extend({
L.U.AutoComplete.Ajax.Select = L.U.AutoComplete.Ajax.extend({
initSelectedContainer: function () {
this.selected_container = L.DomUtil.after(this.input, L.DomUtil.element('div', {className: 'umap-singleresult'}));
var self = this;
if (this.el.selectedIndex !== -1 && this.el[this.el.selectedIndex].value !== '') {
self.displaySelected(self.optionToResult(this.el[this.el.selectedIndex]));
}
return L.DomUtil.after(this.input, L.DomUtil.element('div', {className: 'umap-singleresult'}));
},
displaySelected: function (result) {
var result_el = L.DomUtil.element('div', {}, this.selected_container);
result_el.innerHTML = result.display;
result_el.innerHTML = result.item.label;
var close = L.DomUtil.element('span', {className: 'close'}, result_el);
close.innerHTML = '×';
this.input.style.display = 'none';
L.DomEvent.on(close, 'click', function () {
this.selected_container.innerHTML = '';
this.unselect(result);
this.options.on_unselect(result);
this.input.style.display = 'block';
}, this);
this.hide();
}
});
L.U.AutoComplete.select = function (el, options) {
return new L.U.AutoComplete.Select(el, options);
};

View file

@ -88,7 +88,7 @@ L.U.UpdatePermsAction = L.U.BaseAction.extend({
},
addHooks: function () {
this.map.updatePermissions();
this.map.permissions.panel();
}
});

View file

@ -322,6 +322,7 @@ L.FormBuilder.LicenceChooser = L.FormBuilder.Select.extend({
});
L.FormBuilder.NullableBoolean = L.FormBuilder.Select.extend({
selectOptions: [
[undefined, L._('inherit')],
@ -601,6 +602,61 @@ L.FormBuilder.Range = L.FormBuilder.Input.extend({
});
L.FormBuilder.ManageOwner = L.FormBuilder.Element.extend({
build: function () {
var options = {className: 'edit-owner'};
options.on_select = (choice) => {
this._value = {
'id': choice.item.value,
'name': choice.item.label,
'url': choice.item.url
};
this.set();
}
this.autocomplete = new L.U.AutoComplete.Ajax.Select(this.parentNode, options);
var owner = this.toHTML();
if (owner) this.autocomplete.displaySelected({'item': {'value': owner.id, 'label': owner.name}});
},
value: function () {
return this._value;
}
});
L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
build: function () {
var options = {className: 'edit-editors'};
options.on_select = (choice) => {
this._values.push({
'id': choice.item.value,
'name': choice.item.label,
'url': choice.item.url
});
this.set();
}
options.on_unselect = (choice) => {
var index = this._values.findIndex((item) => item.id === choice.item.value);
if (index !== -1) {
this._values.splice(index, 1);
this.set();
}
}
this.autocomplete = new L.U.AutoComplete.Ajax.SelectMultiple(this.parentNode, options);
this._values = this.toHTML();
if (this._values) for (var i = 0; i < this._values.length; i++) this.autocomplete.displaySelected({'item': {'value': this._values[i].id, 'label': this._values[i].name}});
},
value: function () {
return this._values;
}
});
L.U.FormBuilder = L.FormBuilder.extend({
options: {

View file

@ -198,6 +198,7 @@ L.U.Map.include({
this.help = new L.U.Help(this);
this.slideshow = new L.U.Slideshow(this, this.options.slideshow);
this.permissions = new L.U.MapPermissions(this, this.options.permissions);
this.initCaptionBar();
if (this.options.allowEdit) {
this.editTools = new L.U.Editable(this);
@ -235,9 +236,9 @@ L.U.Map.include({
L.U.EditPropertiesAction,
L.U.ChangeTileLayerAction,
L.U.ManageDatalayersAction,
L.U.UpdateExtentAction
L.U.UpdateExtentAction,
L.U.UpdatePermsAction
];
if (this.options.urls.map_update_permissions) editActions.push(L.U.UpdatePermsAction);
new L.U.SettingsToolbar({actions: editActions}).addTo(this);
}
this._controls.zoom = new L.Control.Zoom({zoomInTitle: L._('Zoom in'), zoomOutTitle: L._('Zoom out')});
@ -345,11 +346,13 @@ L.U.Map.include({
this._backupOptions = L.extend({}, this.options);
this._backupOptions.tilelayer = L.extend({}, this.options.tilelayer);
this._backupOptions.limitBounds = L.extend({}, this.options.limitBounds);
this._backupOptions.permissions = L.extend({}, this.permissions.options);
},
resetOptions: function () {
this.options = L.extend({}, this._backupOptions);
this.options.tilelayer = L.extend({}, this._backupOptions.tilelayer);
this.permissions.options = L.extend({}, this._backupOptions.permissions);
},
initShortcuts: function () {
@ -676,15 +679,6 @@ L.U.Map.include({
return geojson;
},
updatePermissions: function () {
if (!this.options.umap_id) return this.ui.alert({content: L._('Please save the map before'), level: 'info'});
var url = L.Util.template(this.options.urls.map_update_permissions, {'map_id': this.options.umap_id});
this.get(url, {
listen_form: {'id': 'map_edit'},
className: 'dark'
});
},
importPanel: function () {
var container = L.DomUtil.create('div', 'umap-upload'),
title = L.DomUtil.create('h4', '', container),
@ -862,13 +856,7 @@ L.U.Map.include({
var container = L.DomUtil.create('div', 'umap-caption'),
title = L.DomUtil.create('h3', '', container);
title.innerHTML = this.options.name;
if (this.options.author && this.options.author.name && this.options.author.link) {
var authorContainer = L.DomUtil.add('h5', 'umap-map-author', container, L._('by') + ' '),
author = L.DomUtil.create('a');
author.href = this.options.author.link;
author.innerHTML = this.options.author.name;
authorContainer.appendChild(author);
}
this.permissions.addOwnerLink('h5', container);
if (this.options.description) {
var description = L.DomUtil.create('div', 'umap-map-description', container);
description.innerHTML = L.Util.toHTML(this.options.description);
@ -1079,6 +1067,7 @@ L.U.Map.include({
formData.append('settings', JSON.stringify(geojson));
this.post(this.getSaveUrl(), {
data: formData,
context: this,
callback: function (data) {
var duration = 3000;
if (!this.options.umap_id) {
@ -1094,9 +1083,8 @@ L.U.Map.include({
this.ui.alert({content: msg, level: 'info', duration: duration});
});
this.ui.closePanel();
this.continueSaving();
},
context: this
this.permissions.save();
}
});
},
@ -1376,13 +1364,7 @@ L.U.Map.include({
var container = L.DomUtil.create('div', 'umap-caption-bar', this._controlContainer),
name = L.DomUtil.create('h3', '', container);
L.DomEvent.disableClickPropagation(container);
if (this.options.author && this.options.author.name && this.options.author.link) {
var authorContainer = L.DomUtil.add('span', 'umap-map-author', container, ' ' + L._('by') + ' '),
author = L.DomUtil.create('a');
author.href = this.options.author.link;
author.innerHTML = this.options.author.name;
authorContainer.appendChild(author);
}
this.permissions.addOwnerLink('span', container);
var about = L.DomUtil.add('a', 'umap-about-link', container, ' — ' + L._('About'));
about.href = '#';
L.DomEvent.on(about, 'click', this.displayCaption, this);

View file

@ -0,0 +1,119 @@
// Dedicated object so we can deal with a separate dirty status, and thus
// call the endpoint only when needed, saving one call at each save.
L.U.MapPermissions = L.Class.extend({
options: {
owner: null,
editors: [],
share_status: null,
edit_status: null
},
initialize: function (map) {
this.options = map.options.permissions || {};
this.map = map;
var isDirty = false,
self = this;
try {
Object.defineProperty(this, 'isDirty', {
get: function () {
return isDirty;
},
set: function (status) {
isDirty = status;
if (status) self.map.isDirty = status;
}
});
}
catch (e) {
// Certainly IE8, which has a limited version of defineProperty
}
},
isOwner: function () {
return this.map.options.user && this.options.owner && this.map.options.user.id == this.options.owner.id;
},
isAnonymousMap: function () {
return !this.options.owner;
},
getMap: function () {
return this.map;
},
panel: function () {
if (!this.map.options.umap_id) return this.map.ui.alert({content: L._('Please save the map before'), level: 'info'});
var container = L.DomUtil.create('div', 'permissions-panel'),
fields = [],
title = L.DomUtil.create('h4', '', container);
if (this.isAnonymousMap()) {
if (this.map.options.anonymous_edit_url) {
var helpText = L._('Secret edit link is:<br>{link}', {link: this.map.options.anonymous_edit_url});
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.anonymous_edit_statuses, helpText: helpText}]);
}
} else {
if (this.isOwner()) {
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.edit_statuses}]);
fields.push(['options.share_status', {handler: 'IntSelect', label: L._('Who can view'), selectOptions: this.map.options.share_statuses}]);
fields.push(['options.owner', {handler: 'ManageOwner', label: L._("Map's owner")}]);
}
fields.push(['options.editors', {handler: 'ManageEditors', label: L._("Map's editors")}]);
}
title.innerHTML = L._('Update permissions');
var builder = new L.U.FormBuilder(this, fields);
var form = builder.build();
container.appendChild(form);
this.map.ui.openPanel({data: {html: container}, className: 'dark'});
},
anonymousMapPanel: function () {
var container = L.DomUtil.create('div'),
fields = [],
title = L.DomUtil.create('h4', '', container);
fields.push(['options.edit_status', {handler: 'IntSelect', label: L._('Who can edit'), selectOptions: this.map.options.edit_statuses}]);
title.innerHTML = L._('Update permissions');
var builder = new L.U.FormBuilder(this, fields);
var form = builder.build();
container.appendChild(form);
this.map.ui.openPanel({data: {html: container}, className: 'dark'});
},
save: function () {
if (!this.isDirty) return this.map.continueSaving();
var formData = new FormData();
if (!this.isAnonymousMap() && this.options.editors) {
const editors = this.options.editors.map((u) => u.id);
for (var i = 0; i < this.options.editors.length; i++) formData.append('editors', this.options.editors[i].id);
}
if (this.isOwner() || this.isAnonymousMap()) formData.append('edit_status', this.options.edit_status);
if (this.isOwner()) {
formData.append('owner', this.options.owner && this.options.owner.id);
formData.append('share_status', this.options.share_status);
}
this.map.post(this.getUrl(), {
data: formData,
context: this,
callback: function (data) {
this.isDirty = false;
this.map.continueSaving();
}
});
},
getUrl: function () {
return L.Util.template(this.map.options.urls.map_update_permissions, {'map_id': this.map.options.umap_id});
},
addOwnerLink: function (element, container) {
if (this.options.owner && this.options.owner.name && this.options.owner.url) {
var ownerContainer = L.DomUtil.add(element, 'umap-map-owner', container, ' ' + L._('by') + ' '),
owner = L.DomUtil.create('a');
owner.href = this.options.owner.url;
owner.innerHTML = this.options.owner.name;
ownerContainer.appendChild(owner);
}
}
});

View file

@ -1,4 +1,4 @@
describe('L.Utorage.Map', function(){
describe('L.Umap.Map', function(){
before(function () {
this.server = sinon.fakeServer.create();

View file

@ -0,0 +1,77 @@
describe('L.Permissions', function () {
var path = '/map/99/datalayer/edit/62/';
before(function () {
this.server = sinon.fakeServer.create();
this.server.respondWith('GET', '/datalayer/62/', JSON.stringify(RESPONSES.datalayer62_GET));
this.map = initMap({umap_id: 99});
this.datalayer = this.map.getDataLayerByUmapId(62);
this.server.respond();
enableEdit();
});
after(function () {
clickCancel();
this.server.restore();
resetMap();
});
describe('#open()', function () {
var button;
it('should exist update permissions link', function () {
button = qs('a.update-map-permissions');
expect(button).to.be.ok;
});
it('should open table button click', function () {
happen.click(button);
expect(qs('.permissions-panel')).to.be.ok;
});
});
describe('#anonymous with cookie', function () {
var button;
it('should only allow edit_status', function () {
this.map.options.anonymous_edit_url = 'http://anonymous.url'
button = qs('a.update-map-permissions');
happen.click(button);
expect(qs('select[name="edit_status"]')).to.be.ok;
expect(qs('select[name="share_status"]')).not.to.be.ok;
expect(qs('input.edit-owner')).not.to.be.ok;
});
});
describe('#editor', function () {
var button;
it('should only allow editors', function () {
this.map.permissions.options.owner = {id: 1, url: '/url', name: 'jojo'};
button = qs('a.update-map-permissions');
happen.click(button);
expect(qs('select[name="edit_status"]')).not.to.be.ok;
expect(qs('select[name="share_status"]')).not.to.be.ok;
expect(qs('input.edit-owner')).not.to.be.ok;
expect(qs('input.edit-editors')).to.be.ok;
});
});
describe('#owner', function () {
var button;
it('should allow everything', function () {
this.map.permissions.options.owner = {id: 1, url: '/url', name: 'jojo'};
this.map.options.user = {id: 1, url: '/url', name: 'jojo'};
button = qs('a.update-map-permissions');
happen.click(button);
expect(qs('select[name="edit_status"]')).to.be.ok;
expect(qs('select[name="share_status"]')).to.be.ok;
expect(qs('input.edit-owner')).to.be.ok;
expect(qs('input.edit-editors')).to.be.ok;
});
});
});

View file

@ -22,6 +22,7 @@
<script src="../vendors/formbuilder/Leaflet.FormBuilder.js"></script>
<script src="../vendors/measurable/Leaflet.Measurable.js"></script>
<script src="../js/umap.core.js"></script>
<script src="../js/umap.autocomplete.js"></script>
<script src="../js/umap.popup.js"></script>
<script src="../js/umap.xhr.js"></script>
<script src="../js/umap.forms.js"></script>
@ -31,6 +32,7 @@
<script src="../js/umap.controls.js"></script>
<script src="../js/umap.slideshow.js"></script>
<script src="../js/umap.tableeditor.js"></script>
<script src="../js/umap.permissions.js"></script>
<script src="../js/umap.js"></script>
<script src="../js/umap.ui.js"></script>
<link rel="stylesheet" href="../vendors/leaflet/leaflet.css" />
@ -41,8 +43,12 @@
<link rel="stylesheet" href="../vendors/contextmenu/leaflet.contextmenu.css" />
<link rel="stylesheet" href="../vendors/toolbar/leaflet.toolbar.css" />
<link rel="stylesheet" href="../vendors/measurable/Leaflet.Measurable.css" />
<link rel="stylesheet" href="../storage.css" />
<link rel="stylesheet" href="../default.css" />
<link rel="stylesheet" href="../../umap/font.css">
<link rel="stylesheet" href="../../umap/base.css">
<link rel="stylesheet" href="../../umap/content.css">
<link rel="stylesheet" href="../../umap/nav.css">
<link rel="stylesheet" href="../../umap/map.css" />
<link rel="stylesheet" href="../../umap/theme.css">
<script src="../../../../node_modules/sinon/pkg/sinon.js"></script>
<script src="../../../../node_modules/mocha/mocha.js"></script>
@ -68,6 +74,7 @@
<script src="./Polygon.js"></script>
<script src="./Util.js"></script>
<script src="./Controls.js"></script>
<script src="./Permissions.js"></script>
<style type="text/css">
#mocha {
position: absolute;

View file

@ -38,6 +38,7 @@
<script src="{{ STATIC_URL }}umap/js/umap.controls.js"></script>
<script src="{{ STATIC_URL }}umap/js/umap.slideshow.js"></script>
<script src="{{ STATIC_URL }}umap/js/umap.tableeditor.js"></script>
<script src="{{ STATIC_URL }}umap/js/umap.permissions.js"></script>
<script src="{{ STATIC_URL }}umap/js/umap.js"></script>
<script src="{{ STATIC_URL }}umap/js/umap.ui.js"></script>
{% endcompress %}

View file

@ -18,14 +18,4 @@
{% include "umap/map_init.html" %}
{% endblock %}
{% include "umap/map_messages.html" %}
<script type="text/javascript">
MAP.ui.on('panel:ready', function () {
L.U.AutoComplete.multiSelect('id_editors', {
placeholder: "{% trans 'Type editors nick to add…' %}"
});
L.U.AutoComplete.select('id_owner', {
placeholder: "{% trans 'Type new owner nick…' %}"
});
});
</script>
{% endblock %}

View file

@ -1,7 +0,0 @@
{% load i18n %}
<h3>{% trans "Map permissions" %}</h3>
<form action="{% url 'map_update_permissions' map.pk %}" method="post" id="map_edit">
{% csrf_token %}
{{ form }}
<input type="submit" />
</form>

View file

@ -32,6 +32,7 @@ urlpatterns = [
{'template_name': 'umap/password_change_done.html'},
name='password_change_done'),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^agnocomplete/', include('agnocomplete.urls')),
]
i18n_urls = [

View file

@ -339,7 +339,7 @@ class FormLessEditMixin(object):
return simple_json_response(errors=form.errors,
error=str(form.errors))
def get_form(self):
def get_form(self, form_class=None):
kwargs = self.get_form_kwargs()
kwargs['error_class'] = FlatErrorList
return self.get_form_class()(**kwargs)
@ -358,6 +358,11 @@ class MapDetailMixin(object):
'default_iconUrl': "%sumap/img/marker.png" % settings.STATIC_URL, # noqa
'umap_id': self.get_umap_id(),
'licences': dict((l.name, l.json) for l in Licence.objects.all()),
'edit_statuses': [(i, str(label)) for i, label in Map.EDIT_STATUS],
'share_statuses': [(i, str(label))
for i, label in Map.SHARE_STATUS],
'anonymous_edit_statuses': [(i, str(label)) for i, label
in AnonymousMapPermissionsForm.STATUS],
}
if self.get_short_url():
properties['shortUrl'] = self.get_short_url()
@ -448,12 +453,36 @@ class MapView(MapDetailMixin, DetailView):
map_settings = self.object.settings
if "properties" not in map_settings:
map_settings['properties'] = {}
if self.object.owner and hasattr(settings, 'USER_MAPS_URL'):
map_settings['properties']['author'] = {
permissions = {}
permissions['edit_status'] = self.object.edit_status
permissions['share_status'] = self.object.share_status
if self.object.owner:
permissions['owner'] = {
'id': self.object.owner.pk,
'name': self.object.owner.get_username(),
'link': reverse(settings.USER_MAPS_URL,
args=(self.object.owner.get_username(), ))
'url': reverse(settings.USER_MAPS_URL,
args=(self.object.owner.get_username(), ))
}
permissions['editors'] = [{
'id': editor.pk,
'name': editor.get_username(),
} for editor in self.object.editors.all()]
map_settings['properties']['permissions'] = permissions
user = self.request.user
if not user.is_anonymous:
map_settings['properties']['user'] = {
'id': user.pk,
'name': user.get_username(),
'url': reverse(settings.USER_MAPS_URL,
args=(user.get_username(), ))
}
if (not self.object.owner
and self.object.is_anonymous_owner(self.request)):
anonymous_url = "%s%s" % (
settings.SITE_URL,
self.object.get_anonymous_edit_url()
)
map_settings['properties']['anonymous_edit_url'] = anonymous_url
return map_settings
@ -520,8 +549,7 @@ class MapUpdate(FormLessEditMixin, UpdateView):
)
class UpdateMapPermissions(UpdateView):
template_name = "umap/map_update_permissions.html"
class UpdateMapPermissions(FormLessEditMixin, UpdateView):
model = Map
pk_url_kwarg = 'map_id'
@ -532,7 +560,7 @@ class UpdateMapPermissions(UpdateView):
return AnonymousMapPermissionsForm
def get_form(self, form_class=None):
form = super(UpdateMapPermissions, self).get_form(form_class)
form = super().get_form(form_class)
user = self.request.user
if self.object.owner and not user == self.object.owner:
del form.fields['edit_status']
@ -545,10 +573,6 @@ class UpdateMapPermissions(UpdateView):
return simple_json_response(
info=_("Map editors updated with success!"))
def render_to_response(self, context, **response_kwargs):
context.update(response_kwargs)
return render_to_json(self.get_template_names(), context, self.request)
class MapDelete(DeleteView):
model = Map