Move permissions form building to JS
This commit is contained in:
parent
6b3d45064c
commit
48185650b0
18 changed files with 368 additions and 156 deletions
|
@ -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
19
umap/autocomplete.py
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
_do_search: function (val, callback) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -88,7 +88,7 @@ L.U.UpdatePermsAction = L.U.BaseAction.extend({
|
|||
},
|
||||
|
||||
addHooks: function () {
|
||||
this.map.updatePermissions();
|
||||
this.map.permissions.panel();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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);
|
||||
|
|
119
umap/static/umap/js/umap.permissions.js
Normal file
119
umap/static/umap/js/umap.permissions.js
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
describe('L.Utorage.Map', function(){
|
||||
describe('L.Umap.Map', function(){
|
||||
|
||||
before(function () {
|
||||
this.server = sinon.fakeServer.create();
|
||||
|
|
77
umap/static/umap/test/Permissions.js
Normal file
77
umap/static/umap/test/Permissions.js
Normal 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;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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>
|
|
@ -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 = [
|
||||
|
|
|
@ -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,
|
||||
'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
|
||||
|
|
Loading…
Reference in a new issue