mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 11:52:38 +02:00
wip: use auth.models.Group and manage permissions
This commit is contained in:
parent
6126a6666e
commit
dce0ee5f73
15 changed files with 237 additions and 34 deletions
|
@ -35,7 +35,7 @@ def can_edit_map(view_func):
|
||||||
map_inst = get_object_or_404(Map, pk=kwargs["map_id"])
|
map_inst = get_object_or_404(Map, pk=kwargs["map_id"])
|
||||||
user = request.user
|
user = request.user
|
||||||
kwargs["map_inst"] = map_inst # Avoid rerequesting the map in the view
|
kwargs["map_inst"] = map_inst # Avoid rerequesting the map in the view
|
||||||
if map_inst.edit_status >= map_inst.EDITORS:
|
if map_inst.edit_status >= map_inst.COLLABORATORS:
|
||||||
can_edit = map_inst.can_edit(user=user, request=request)
|
can_edit = map_inst.can_edit(user=user, request=request)
|
||||||
if not can_edit:
|
if not can_edit:
|
||||||
if map_inst.owner and not user.is_authenticated:
|
if map_inst.owner and not user.is_authenticated:
|
||||||
|
|
|
@ -36,7 +36,7 @@ class SendLinkForm(forms.Form):
|
||||||
class UpdateMapPermissionsForm(forms.ModelForm):
|
class UpdateMapPermissionsForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Map
|
model = Map
|
||||||
fields = ("edit_status", "editors", "share_status", "owner")
|
fields = ("edit_status", "editors", "share_status", "owner", "group")
|
||||||
|
|
||||||
|
|
||||||
class AnonymousMapPermissionsForm(forms.ModelForm):
|
class AnonymousMapPermissionsForm(forms.ModelForm):
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Generated by Django 5.1 on 2024-08-15 11:33
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import umap.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("auth", "0012_alter_user_first_name_max_length"),
|
||||||
|
("umap", "0021_remove_map_description"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="map",
|
||||||
|
name="group",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="auth.group",
|
||||||
|
verbose_name="group",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="datalayer",
|
||||||
|
name="edit_status",
|
||||||
|
field=models.SmallIntegerField(
|
||||||
|
choices=[
|
||||||
|
(0, "Inherit"),
|
||||||
|
(1, "Everyone"),
|
||||||
|
(2, "Editors and team only"),
|
||||||
|
(3, "Owner only"),
|
||||||
|
],
|
||||||
|
default=0,
|
||||||
|
verbose_name="edit status",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="map",
|
||||||
|
name="edit_status",
|
||||||
|
field=models.SmallIntegerField(
|
||||||
|
choices=[
|
||||||
|
(1, "Everyone"),
|
||||||
|
(2, "Editors and team only"),
|
||||||
|
(3, "Owner only"),
|
||||||
|
],
|
||||||
|
default=umap.models.get_default_edit_status,
|
||||||
|
verbose_name="edit status",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="map",
|
||||||
|
name="share_status",
|
||||||
|
field=models.SmallIntegerField(
|
||||||
|
choices=[
|
||||||
|
(1, "Everyone (public)"),
|
||||||
|
(2, "Anyone with link"),
|
||||||
|
(3, "Editors and team only"),
|
||||||
|
(9, "Blocked"),
|
||||||
|
],
|
||||||
|
default=umap.models.get_default_share_status,
|
||||||
|
verbose_name="share status",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -5,7 +5,7 @@ import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.core.files.base import File
|
from django.core.files.base import File
|
||||||
from django.core.signing import Signer
|
from django.core.signing import Signer
|
||||||
|
@ -36,9 +36,19 @@ def get_user_stars_url(self):
|
||||||
return reverse("user_stars", kwargs={"identifier": identifier})
|
return reverse("user_stars", kwargs={"identifier": identifier})
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_url(self):
|
||||||
|
return "TODO"
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_metadata(self):
|
||||||
|
return {"id": self.pk, "name": self.name, "url": self.get_url()}
|
||||||
|
|
||||||
|
|
||||||
User.add_to_class("__str__", display_name)
|
User.add_to_class("__str__", display_name)
|
||||||
User.add_to_class("get_url", get_user_url)
|
User.add_to_class("get_url", get_user_url)
|
||||||
User.add_to_class("get_stars_url", get_user_stars_url)
|
User.add_to_class("get_stars_url", get_user_stars_url)
|
||||||
|
Group.add_to_class("get_url", get_group_url)
|
||||||
|
Group.add_to_class("get_metadata", get_group_metadata)
|
||||||
|
|
||||||
|
|
||||||
def get_default_share_status():
|
def get_default_share_status():
|
||||||
|
@ -137,7 +147,7 @@ class Map(NamedModel):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ANONYMOUS = 1
|
ANONYMOUS = 1
|
||||||
EDITORS = 2
|
COLLABORATORS = 2
|
||||||
OWNER = 3
|
OWNER = 3
|
||||||
PUBLIC = 1
|
PUBLIC = 1
|
||||||
OPEN = 2
|
OPEN = 2
|
||||||
|
@ -145,13 +155,13 @@ class Map(NamedModel):
|
||||||
BLOCKED = 9
|
BLOCKED = 9
|
||||||
EDIT_STATUS = (
|
EDIT_STATUS = (
|
||||||
(ANONYMOUS, _("Everyone")),
|
(ANONYMOUS, _("Everyone")),
|
||||||
(EDITORS, _("Editors only")),
|
(COLLABORATORS, _("Editors and team only")),
|
||||||
(OWNER, _("Owner only")),
|
(OWNER, _("Owner only")),
|
||||||
)
|
)
|
||||||
SHARE_STATUS = (
|
SHARE_STATUS = (
|
||||||
(PUBLIC, _("Everyone (public)")),
|
(PUBLIC, _("Everyone (public)")),
|
||||||
(OPEN, _("Anyone with link")),
|
(OPEN, _("Anyone with link")),
|
||||||
(PRIVATE, _("Editors only")),
|
(PRIVATE, _("Editors and team only")),
|
||||||
(BLOCKED, _("Blocked")),
|
(BLOCKED, _("Blocked")),
|
||||||
)
|
)
|
||||||
slug = models.SlugField(db_index=True)
|
slug = models.SlugField(db_index=True)
|
||||||
|
@ -180,6 +190,13 @@ class Map(NamedModel):
|
||||||
editors = models.ManyToManyField(
|
editors = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL, blank=True, verbose_name=_("editors")
|
settings.AUTH_USER_MODEL, blank=True, verbose_name=_("editors")
|
||||||
)
|
)
|
||||||
|
group = models.ForeignKey(
|
||||||
|
"auth.Group",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name=_("team"),
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
)
|
||||||
edit_status = models.SmallIntegerField(
|
edit_status = models.SmallIntegerField(
|
||||||
choices=EDIT_STATUS,
|
choices=EDIT_STATUS,
|
||||||
default=get_default_edit_status,
|
default=get_default_edit_status,
|
||||||
|
@ -281,7 +298,7 @@ class Map(NamedModel):
|
||||||
|
|
||||||
In owner mode:
|
In owner mode:
|
||||||
- only owner by default (OWNER)
|
- only owner by default (OWNER)
|
||||||
- any editor if mode is EDITORS
|
- any editor or group member if mode is COLLABORATORS
|
||||||
- anyone otherwise (ANONYMOUS)
|
- anyone otherwise (ANONYMOUS)
|
||||||
In anonymous owner mode:
|
In anonymous owner mode:
|
||||||
- only owner (has ownership cookie) by default (OWNER)
|
- only owner (has ownership cookie) by default (OWNER)
|
||||||
|
@ -297,8 +314,9 @@ class Map(NamedModel):
|
||||||
can = False
|
can = False
|
||||||
elif user == self.owner:
|
elif user == self.owner:
|
||||||
can = True
|
can = True
|
||||||
elif self.edit_status == self.EDITORS and user in self.editors.all():
|
elif self.edit_status == self.COLLABORATORS:
|
||||||
can = True
|
if user in self.editors.all() or self.group in user.groups.all():
|
||||||
|
can = True
|
||||||
return can
|
return can
|
||||||
|
|
||||||
def can_view(self, request):
|
def can_view(self, request):
|
||||||
|
@ -308,12 +326,15 @@ class Map(NamedModel):
|
||||||
can = True
|
can = True
|
||||||
elif self.share_status in [self.PUBLIC, self.OPEN]:
|
elif self.share_status in [self.PUBLIC, self.OPEN]:
|
||||||
can = True
|
can = True
|
||||||
|
elif request.user is None:
|
||||||
|
can = False
|
||||||
elif request.user == self.owner:
|
elif request.user == self.owner:
|
||||||
can = True
|
can = True
|
||||||
else:
|
else:
|
||||||
can = not (
|
can = not (
|
||||||
self.share_status == self.PRIVATE
|
self.share_status == self.PRIVATE
|
||||||
and request.user not in self.editors.all()
|
and request.user not in self.editors.all()
|
||||||
|
and self.group not in request.user.groups.all()
|
||||||
)
|
)
|
||||||
return can
|
return can
|
||||||
|
|
||||||
|
@ -383,12 +404,12 @@ class DataLayer(NamedModel):
|
||||||
|
|
||||||
INHERIT = 0
|
INHERIT = 0
|
||||||
ANONYMOUS = 1
|
ANONYMOUS = 1
|
||||||
EDITORS = 2
|
COLLABORATORS = 2
|
||||||
OWNER = 3
|
OWNER = 3
|
||||||
EDIT_STATUS = (
|
EDIT_STATUS = (
|
||||||
(INHERIT, _("Inherit")),
|
(INHERIT, _("Inherit")),
|
||||||
(ANONYMOUS, _("Everyone")),
|
(ANONYMOUS, _("Everyone")),
|
||||||
(EDITORS, _("Editors only")),
|
(COLLABORATORS, _("Editors and team only")),
|
||||||
(OWNER, _("Owner only")),
|
(OWNER, _("Owner only")),
|
||||||
)
|
)
|
||||||
uuid = models.UUIDField(
|
uuid = models.UUIDField(
|
||||||
|
@ -538,8 +559,9 @@ class DataLayer(NamedModel):
|
||||||
can = True
|
can = True
|
||||||
elif user is not None and user == self.map.owner:
|
elif user is not None and user == self.map.owner:
|
||||||
can = True
|
can = True
|
||||||
elif self.edit_status == self.EDITORS and user in self.map.editors.all():
|
elif user is not None and self.edit_status == self.COLLABORATORS:
|
||||||
can = True
|
if user in self.map.editors.all() or self.map.group in user.groups.all():
|
||||||
|
can = True
|
||||||
return can
|
return can
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ export class MapPermissions {
|
||||||
this.options = Object.assign(
|
this.options = Object.assign(
|
||||||
{
|
{
|
||||||
owner: null,
|
owner: null,
|
||||||
|
group: null,
|
||||||
editors: [],
|
editors: [],
|
||||||
share_status: null,
|
share_status: null,
|
||||||
edit_status: null,
|
edit_status: null,
|
||||||
|
@ -96,6 +97,16 @@ export class MapPermissions {
|
||||||
'options.owner',
|
'options.owner',
|
||||||
{ handler: 'ManageOwner', label: translate("Map's owner") },
|
{ handler: 'ManageOwner', label: translate("Map's owner") },
|
||||||
])
|
])
|
||||||
|
if (this.map.options.user?.groups?.length) {
|
||||||
|
fields.push([
|
||||||
|
'options.group',
|
||||||
|
{
|
||||||
|
handler: 'ManageGroup',
|
||||||
|
label: translate('Attach map to a team'),
|
||||||
|
groups: this.map.options.user.groups,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fields.push([
|
fields.push([
|
||||||
'options.editors',
|
'options.editors',
|
||||||
|
@ -150,6 +161,7 @@ export class MapPermissions {
|
||||||
formData.append('edit_status', this.options.edit_status)
|
formData.append('edit_status', this.options.edit_status)
|
||||||
if (this.isOwner()) {
|
if (this.isOwner()) {
|
||||||
formData.append('owner', this.options.owner?.id)
|
formData.append('owner', this.options.owner?.id)
|
||||||
|
formData.append('group', this.options.group?.id || '')
|
||||||
formData.append('share_status', this.options.share_status)
|
formData.append('share_status', this.options.share_status)
|
||||||
}
|
}
|
||||||
const [data, response, error] = await this.map.server.post(
|
const [data, response, error] = await this.map.server.post(
|
||||||
|
|
|
@ -1086,6 +1086,23 @@ L.FormBuilder.ManageEditors = L.FormBuilder.Element.extend({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
L.FormBuilder.ManageGroup = L.FormBuilder.IntSelect.extend({
|
||||||
|
getOptions: function () {
|
||||||
|
return [[null, L._('None')]].concat(
|
||||||
|
this.options.groups.map((group) => [group.id, group.name])
|
||||||
|
)
|
||||||
|
},
|
||||||
|
toHTML: function () {
|
||||||
|
return this.get()?.id
|
||||||
|
},
|
||||||
|
toJS: function () {
|
||||||
|
const value = this.value()
|
||||||
|
for (const group of this.options.groups) {
|
||||||
|
if (group.id === value) return group
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
U.FormBuilder = L.FormBuilder.extend({
|
U.FormBuilder = L.FormBuilder.extend({
|
||||||
options: {
|
options: {
|
||||||
className: 'umap-form',
|
className: 'umap-form',
|
||||||
|
|
|
@ -3,6 +3,7 @@ import json
|
||||||
|
|
||||||
import factory
|
import factory
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.contrib.auth.models import Group
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
|
@ -58,6 +59,13 @@ class UserFactory(factory.django.DjangoModelFactory):
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
|
|
||||||
|
class GroupFactory(factory.django.DjangoModelFactory):
|
||||||
|
name = "Awesome Group"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Group
|
||||||
|
|
||||||
|
|
||||||
class MapFactory(factory.django.DjangoModelFactory):
|
class MapFactory(factory.django.DjangoModelFactory):
|
||||||
name = "test map"
|
name = "test map"
|
||||||
slug = "test-map"
|
slug = "test-map"
|
||||||
|
|
|
@ -9,6 +9,7 @@ from umap.models import Map
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
DataLayerFactory,
|
DataLayerFactory,
|
||||||
|
GroupFactory,
|
||||||
LicenceFactory,
|
LicenceFactory,
|
||||||
MapFactory,
|
MapFactory,
|
||||||
TileLayerFactory,
|
TileLayerFactory,
|
||||||
|
@ -29,6 +30,11 @@ def pytest_runtest_teardown():
|
||||||
cache.clear()
|
cache.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def group():
|
||||||
|
return GroupFactory()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def user():
|
def user():
|
||||||
return UserFactory(password="123123")
|
return UserFactory(password="123123")
|
||||||
|
|
|
@ -81,7 +81,7 @@ def test_owner_permissions_form(map, datalayer, live_server, login):
|
||||||
|
|
||||||
|
|
||||||
def test_map_update_with_editor(map, live_server, login, user):
|
def test_map_update_with_editor(map, live_server, login, user):
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
page = login(user)
|
page = login(user)
|
||||||
|
@ -104,7 +104,7 @@ def test_map_update_with_editor(map, live_server, login, user):
|
||||||
|
|
||||||
|
|
||||||
def test_permissions_form_with_editor(map, datalayer, live_server, login, user):
|
def test_permissions_form_with_editor(map, datalayer, live_server, login, user):
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
page = login(user)
|
page = login(user)
|
||||||
|
@ -141,7 +141,7 @@ def test_owner_has_delete_map_button(map, live_server, login):
|
||||||
|
|
||||||
|
|
||||||
def test_editor_do_not_have_delete_map_button(map, live_server, login, user):
|
def test_editor_do_not_have_delete_map_button(map, live_server, login, user):
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
page = login(user)
|
page = login(user)
|
||||||
|
@ -241,3 +241,19 @@ def test_can_delete_datalayer(live_server, map, login, datalayer):
|
||||||
expect(markers).to_have_count(0)
|
expect(markers).to_have_count(0)
|
||||||
# FIXME does not work, resolve to 1 element, even if this command is empty:
|
# FIXME does not work, resolve to 1 element, even if this command is empty:
|
||||||
expect(layers).to_have_count(0)
|
expect(layers).to_have_count(0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_set_group(map, live_server, login, group):
|
||||||
|
map.owner.groups.add(group)
|
||||||
|
map.owner.save()
|
||||||
|
page = login(map.owner)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
edit_permissions = page.get_by_title("Update permissions and editors")
|
||||||
|
edit_permissions.click()
|
||||||
|
page.locator("select[name=group]").select_option(str(group.pk))
|
||||||
|
save = page.get_by_role("button", name="Save")
|
||||||
|
expect(save).to_be_visible()
|
||||||
|
with page.expect_response(re.compile(r".*/update/permissions/.*")):
|
||||||
|
save.click()
|
||||||
|
modified = Map.objects.get(pk=map.pk)
|
||||||
|
assert modified.group == group
|
||||||
|
|
|
@ -101,22 +101,33 @@ def test_should_remove_old_versions_on_save(map, settings):
|
||||||
|
|
||||||
|
|
||||||
def test_anonymous_cannot_edit_in_editors_mode(datalayer):
|
def test_anonymous_cannot_edit_in_editors_mode(datalayer):
|
||||||
datalayer.edit_status = DataLayer.EDITORS
|
datalayer.edit_status = DataLayer.COLLABORATORS
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
assert not datalayer.can_edit()
|
assert not datalayer.can_edit()
|
||||||
|
|
||||||
|
|
||||||
def test_owner_can_edit_in_editors_mode(datalayer, user):
|
def test_owner_can_edit_in_editors_mode(datalayer, user):
|
||||||
datalayer.edit_status = DataLayer.EDITORS
|
datalayer.edit_status = DataLayer.COLLABORATORS
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
assert datalayer.can_edit(datalayer.map.owner)
|
assert datalayer.can_edit(datalayer.map.owner)
|
||||||
|
|
||||||
|
|
||||||
def test_editor_can_edit_in_editors_mode(datalayer, user):
|
def test_editor_can_edit_in_collaborators_mode(datalayer, user):
|
||||||
map = datalayer.map
|
map = datalayer.map
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
datalayer.edit_status = DataLayer.EDITORS
|
datalayer.edit_status = DataLayer.COLLABORATORS
|
||||||
|
datalayer.save()
|
||||||
|
assert datalayer.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_group_members_can_edit_in_collaborators_mode(datalayer, user, group):
|
||||||
|
user.groups.add(group)
|
||||||
|
user.save()
|
||||||
|
map = datalayer.map
|
||||||
|
map.group = group
|
||||||
|
map.save()
|
||||||
|
datalayer.edit_status = DataLayer.COLLABORATORS
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
assert datalayer.can_edit(user)
|
assert datalayer.can_edit(user)
|
||||||
|
|
||||||
|
@ -170,6 +181,20 @@ def test_editors_cannot_edit_in_inherit_mode_and_map_in_owner_mode(datalayer, us
|
||||||
assert not datalayer.can_edit(user)
|
assert not datalayer.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_group_members_cannot_edit_in_inherit_mode_and_map_in_owner_mode(
|
||||||
|
datalayer, user, group
|
||||||
|
):
|
||||||
|
datalayer.edit_status = DataLayer.INHERIT
|
||||||
|
datalayer.save()
|
||||||
|
user.groups.add(group)
|
||||||
|
group.save()
|
||||||
|
map = datalayer.map
|
||||||
|
map.group = group
|
||||||
|
map.edit_status = Map.OWNER
|
||||||
|
map.save()
|
||||||
|
assert not datalayer.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
def test_anonymous_cannot_edit_in_inherit_mode_and_map_in_owner_mode(datalayer):
|
def test_anonymous_cannot_edit_in_inherit_mode_and_map_in_owner_mode(datalayer):
|
||||||
datalayer.edit_status = DataLayer.INHERIT
|
datalayer.edit_status = DataLayer.INHERIT
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
|
@ -183,7 +208,7 @@ def test_owner_can_edit_in_inherit_mode_and_map_in_editors_mode(datalayer):
|
||||||
datalayer.edit_status = DataLayer.INHERIT
|
datalayer.edit_status = DataLayer.INHERIT
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
map = datalayer.map
|
map = datalayer.map
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.save()
|
map.save()
|
||||||
assert datalayer.can_edit(map.owner)
|
assert datalayer.can_edit(map.owner)
|
||||||
|
|
||||||
|
@ -193,7 +218,7 @@ def test_editors_can_edit_in_inherit_mode_and_map_in_editors_mode(datalayer, use
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
map = datalayer.map
|
map = datalayer.map
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.save()
|
map.save()
|
||||||
assert datalayer.can_edit(user)
|
assert datalayer.can_edit(user)
|
||||||
|
|
||||||
|
@ -202,7 +227,7 @@ def test_anonymous_cannot_edit_in_inherit_mode_and_map_in_editors_mode(datalayer
|
||||||
datalayer.edit_status = DataLayer.INHERIT
|
datalayer.edit_status = DataLayer.INHERIT
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
map = datalayer.map
|
map = datalayer.map
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.save()
|
map.save()
|
||||||
assert not datalayer.can_edit()
|
assert not datalayer.can_edit()
|
||||||
|
|
||||||
|
|
|
@ -379,7 +379,7 @@ def test_owner_can_edit_in_owner_mode(datalayer, client, map, post_data):
|
||||||
|
|
||||||
def test_editor_can_edit_in_editors_mode(datalayer, client, map, post_data):
|
def test_editor_can_edit_in_editors_mode(datalayer, client, map, post_data):
|
||||||
client.login(username=map.owner.username, password="123123")
|
client.login(username=map.owner.username, password="123123")
|
||||||
datalayer.edit_status = DataLayer.EDITORS
|
datalayer.edit_status = DataLayer.COLLABORATORS
|
||||||
datalayer.save()
|
datalayer.save()
|
||||||
url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
|
url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
|
||||||
name = "new name"
|
name = "new name"
|
||||||
|
|
|
@ -43,13 +43,31 @@ def test_editors_cannot_edit_if_status_owner(map, user):
|
||||||
assert not map.can_edit(user)
|
assert not map.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
def test_editors_can_edit_if_status_editors(map, user):
|
def test_editors_can_edit_if_status_collaborators(map, user):
|
||||||
map.edit_status = map.EDITORS
|
map.edit_status = map.COLLABORATORS
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
assert map.can_edit(user)
|
assert map.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_group_members_cannot_edit_if_status_owner(map, user, group):
|
||||||
|
user.groups.add(group)
|
||||||
|
user.save()
|
||||||
|
map.edit_status = map.OWNER
|
||||||
|
map.group = group
|
||||||
|
map.save()
|
||||||
|
assert not map.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_group_members_can_edit_if_status_collaborators(map, user, group):
|
||||||
|
user.groups.add(group)
|
||||||
|
user.save()
|
||||||
|
map.edit_status = map.COLLABORATORS
|
||||||
|
map.group = group
|
||||||
|
map.save()
|
||||||
|
assert map.can_edit(user)
|
||||||
|
|
||||||
|
|
||||||
def test_logged_in_user_should_be_allowed_for_anonymous_map_with_anonymous_edit_status(
|
def test_logged_in_user_should_be_allowed_for_anonymous_map_with_anonymous_edit_status(
|
||||||
map, user, rf
|
map, user, rf
|
||||||
): # noqa
|
): # noqa
|
||||||
|
@ -87,6 +105,14 @@ def test_clone_should_keep_editors(map, user):
|
||||||
assert user in clone.editors.all()
|
assert user in clone.editors.all()
|
||||||
|
|
||||||
|
|
||||||
|
def test_clone_should_keep_group(map, user, group):
|
||||||
|
map.group = group
|
||||||
|
map.save()
|
||||||
|
clone = map.clone()
|
||||||
|
assert map.pk != clone.pk
|
||||||
|
assert clone.group == group
|
||||||
|
|
||||||
|
|
||||||
def test_clone_should_update_owner_if_passed(map, user):
|
def test_clone_should_update_owner_if_passed(map, user):
|
||||||
clone = map.clone(owner=user)
|
clone = map.clone(owner=user)
|
||||||
assert map.pk != clone.pk
|
assert map.pk != clone.pk
|
||||||
|
@ -119,9 +145,9 @@ def test_publicmanager_should_get_only_public_maps(map, user, licence):
|
||||||
def test_can_change_default_edit_status(user, settings):
|
def test_can_change_default_edit_status(user, settings):
|
||||||
map = MapFactory(owner=user)
|
map = MapFactory(owner=user)
|
||||||
assert map.edit_status == Map.OWNER
|
assert map.edit_status == Map.OWNER
|
||||||
settings.UMAP_DEFAULT_EDIT_STATUS = Map.EDITORS
|
settings.UMAP_DEFAULT_EDIT_STATUS = Map.COLLABORATORS
|
||||||
map = MapFactory(owner=user)
|
map = MapFactory(owner=user)
|
||||||
assert map.edit_status == Map.EDITORS
|
assert map.edit_status == Map.COLLABORATORS
|
||||||
|
|
||||||
|
|
||||||
def test_can_change_default_share_status(user, settings):
|
def test_can_change_default_share_status(user, settings):
|
||||||
|
|
|
@ -210,7 +210,7 @@ def test_user_not_allowed_should_not_clone_map(client, map, user, settings):
|
||||||
|
|
||||||
def test_clone_should_set_cloner_as_owner(client, map, user):
|
def test_clone_should_set_cloner_as_owner(client, map, user):
|
||||||
url = reverse("map_clone", kwargs={"map_id": map.pk})
|
url = reverse("map_clone", kwargs={"map_id": map.pk})
|
||||||
map.edit_status = map.EDITORS
|
map.edit_status = map.COLLABORATORS
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.save()
|
map.save()
|
||||||
client.login(username=user.username, password="123123")
|
client.login(username=user.username, password="123123")
|
||||||
|
@ -330,7 +330,7 @@ def test_only_owner_can_delete(client, map, user):
|
||||||
|
|
||||||
def test_map_editors_do_not_see_owner_change_input(client, map, user):
|
def test_map_editors_do_not_see_owner_change_input(client, map, user):
|
||||||
map.editors.add(user)
|
map.editors.add(user)
|
||||||
map.edit_status = map.EDITORS
|
map.edit_status = map.COLLABORATORS
|
||||||
map.save()
|
map.save()
|
||||||
url = reverse("map_update_permissions", kwargs={"map_id": map.pk})
|
url = reverse("map_update_permissions", kwargs={"map_id": map.pk})
|
||||||
client.login(username=user.username, password="123123")
|
client.login(username=user.username, password="123123")
|
||||||
|
|
|
@ -474,7 +474,7 @@ def test_websocket_token_returns_a_valid_token_when_authorized(client, user, map
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_websocket_token_is_generated_for_editors(client, user, user2, map):
|
def test_websocket_token_is_generated_for_editors(client, user, user2, map):
|
||||||
map.edit_status = Map.EDITORS
|
map.edit_status = Map.COLLABORATORS
|
||||||
map.editors.add(user2)
|
map.editors.add(user2)
|
||||||
map.save()
|
map.save()
|
||||||
|
|
||||||
|
|
|
@ -459,14 +459,16 @@ def simple_json_response(**kwargs):
|
||||||
class SessionMixin:
|
class SessionMixin:
|
||||||
def get_user_data(self):
|
def get_user_data(self):
|
||||||
data = {}
|
data = {}
|
||||||
|
user = self.request.user
|
||||||
if hasattr(self, "object"):
|
if hasattr(self, "object"):
|
||||||
data["is_owner"] = self.object.is_owner(self.request.user, self.request)
|
data["is_owner"] = self.object.is_owner(user, self.request)
|
||||||
if self.request.user.is_anonymous:
|
if user.is_anonymous:
|
||||||
return data
|
return data
|
||||||
return {
|
return {
|
||||||
"id": self.request.user.pk,
|
"id": user.pk,
|
||||||
"name": str(self.request.user),
|
"name": str(self.request.user),
|
||||||
"url": reverse("user_dashboard"),
|
"url": reverse("user_dashboard"),
|
||||||
|
"groups": [group.get_metadata() for group in user.groups.all()],
|
||||||
**data,
|
**data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,6 +607,8 @@ class PermissionsMixin:
|
||||||
{"id": editor.pk, "name": str(editor)}
|
{"id": editor.pk, "name": str(editor)}
|
||||||
for editor in self.object.editors.all()
|
for editor in self.object.editors.all()
|
||||||
]
|
]
|
||||||
|
if self.object.group:
|
||||||
|
permissions["group"] = self.object.group.get_metadata()
|
||||||
if not self.object.owner and self.object.is_anonymous_owner(self.request):
|
if not self.object.owner and self.object.is_anonymous_owner(self.request):
|
||||||
permissions["anonymous_edit_url"] = self.object.get_anonymous_edit_url()
|
permissions["anonymous_edit_url"] = self.object.get_anonymous_edit_url()
|
||||||
return permissions
|
return permissions
|
||||||
|
|
Loading…
Reference in a new issue