Refine collection visibility and team selection
This commit is contained in:
+42
-17
@@ -173,7 +173,11 @@ def desired_item_scope(item, user, force_private=False):
|
||||
|
||||
def item_scope_fits_collections(item, visibility, team):
|
||||
sections = item.collection_sections.select_related('collection') if item.pk else CollectionSection.objects.none()
|
||||
return not any(section.collection.visibility != visibility or section.collection.team_id != (team.id if team else None) for section in sections)
|
||||
team_id = team.id if team else None
|
||||
return all(collection_scope_allows_item(
|
||||
section.collection.visibility, section.collection.team_id, section.collection.owner_id,
|
||||
visibility, team_id, item.owner_id,
|
||||
) for section in sections)
|
||||
|
||||
|
||||
def apply_team_from_tags(item, user, force_private=False):
|
||||
@@ -546,10 +550,22 @@ def user_can_delete_collection(user, collection):
|
||||
return user.is_authenticated and (collection.owner_id == user.id or (collection.team_id and TeamMembership.objects.filter(team=collection.team, user=user, role__in=[TeamMembership.Role.OWNER, TeamMembership.Role.ADMIN]).exists()))
|
||||
|
||||
|
||||
def collection_scope_allows_item(collection_visibility, collection_team_id, collection_owner_id, item_visibility, item_team_id, item_owner_id):
|
||||
# A collection may reference a note that is already visible to a wider audience.
|
||||
if item_visibility == Item.Visibility.PUBLIC:
|
||||
return True
|
||||
if collection_visibility == Item.Visibility.PUBLIC:
|
||||
return False
|
||||
if collection_visibility == Item.Visibility.TEAM:
|
||||
return item_visibility == Item.Visibility.TEAM and item_team_id == collection_team_id
|
||||
return item_visibility == Item.Visibility.PRIVATE and item_owner_id == collection_owner_id
|
||||
|
||||
|
||||
def collection_item_is_compatible(collection, item):
|
||||
if collection.visibility == Item.Visibility.TEAM:
|
||||
return item.visibility == Item.Visibility.TEAM and item.team_id == collection.team_id
|
||||
return item.visibility == collection.visibility and item.team_id is None
|
||||
return collection_scope_allows_item(
|
||||
collection.visibility, collection.team_id, collection.owner_id,
|
||||
item.visibility, item.team_id, item.owner_id,
|
||||
)
|
||||
|
||||
|
||||
def collection_target_from_form(form, user):
|
||||
@@ -564,9 +580,13 @@ def collection_target_from_form(form, user):
|
||||
def item_can_change_for_collection(user, item, collection):
|
||||
if not user_can_edit_item(user, item):
|
||||
return False
|
||||
target_team_id = collection.team_id
|
||||
for section in item.collection_sections.select_related('collection').exclude(collection=collection):
|
||||
other = section.collection
|
||||
if other.visibility != collection.visibility or other.team_id != collection.team_id:
|
||||
if not collection_scope_allows_item(
|
||||
other.visibility, other.team_id, other.owner_id,
|
||||
collection.visibility, target_team_id, item.owner_id,
|
||||
):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -610,12 +630,18 @@ def add_collection_section(collection, item):
|
||||
)
|
||||
|
||||
|
||||
def editable_collection_notes(user):
|
||||
return Item.objects.select_related('owner', 'team').prefetch_related('tags', 'attachments').filter(
|
||||
kind=Item.Kind.NOTE,
|
||||
).filter(Q(owner=user) | Q(team_id__in=user_team_ids(user))).distinct()
|
||||
|
||||
|
||||
def collection_detail_context(request, collection, pending_item=None):
|
||||
can_edit = user_can_edit_collection(request.user, collection)
|
||||
q = request.GET.get('q', '').strip()
|
||||
candidates = Item.objects.none()
|
||||
if can_edit:
|
||||
candidates = visible_items(request.user).filter(kind=Item.Kind.NOTE).exclude(collection_sections__collection=collection)
|
||||
candidates = editable_collection_notes(request.user).exclude(collection_sections__collection=collection)
|
||||
if q:
|
||||
candidates = candidates.filter(Q(content__icontains=q) | Q(tags__name__icontains=q)).distinct()
|
||||
candidates = candidates[:30]
|
||||
@@ -640,7 +666,7 @@ def collection_list(request):
|
||||
@login_required
|
||||
def collection_create(request):
|
||||
if request.method == 'POST':
|
||||
form = CollectionForm(request.POST)
|
||||
form = CollectionForm(request.POST, user=request.user)
|
||||
if form.is_valid():
|
||||
visibility, team = collection_target_from_form(form, request.user)
|
||||
if visibility == Item.Visibility.TEAM and not team:
|
||||
@@ -655,7 +681,7 @@ def collection_create(request):
|
||||
messages.success(request, _('Collection created.'))
|
||||
return redirect(collection)
|
||||
else:
|
||||
form = CollectionForm()
|
||||
form = CollectionForm(user=request.user)
|
||||
return render(request, 'core/collection_form.html', {'form': form, 'heading': _('Create collection')})
|
||||
|
||||
|
||||
@@ -665,15 +691,14 @@ def collection_edit(request, pk):
|
||||
if not user_can_edit_collection(request.user, collection):
|
||||
return JsonResponse({'error': 'forbidden'}, status=403)
|
||||
if request.method == 'POST':
|
||||
form = CollectionForm(request.POST, instance=collection)
|
||||
form = CollectionForm(request.POST, instance=collection, user=request.user)
|
||||
if form.is_valid():
|
||||
visibility, team = collection_target_from_form(form, request.user)
|
||||
incompatible = collection.sections.exclude(item__visibility=visibility)
|
||||
if team:
|
||||
incompatible = incompatible | collection.sections.exclude(item__team=team)
|
||||
else:
|
||||
incompatible = incompatible | collection.sections.exclude(item__team__isnull=True)
|
||||
if incompatible.exists():
|
||||
incompatible = any(not collection_scope_allows_item(
|
||||
visibility, team.id if team else None, collection.owner_id,
|
||||
section.item.visibility, section.item.team_id, section.item.owner_id,
|
||||
) for section in collection.sections.select_related('item'))
|
||||
if incompatible:
|
||||
form.add_error(None, _('The collection visibility cannot change while it contains incompatible notes.'))
|
||||
elif visibility == Item.Visibility.TEAM and not team:
|
||||
form.add_error('visibility', _('Select a team tag for a team collection.'))
|
||||
@@ -686,7 +711,7 @@ def collection_edit(request, pk):
|
||||
messages.success(request, _('Collection saved.'))
|
||||
return redirect(collection)
|
||||
else:
|
||||
form = CollectionForm(instance=collection)
|
||||
form = CollectionForm(instance=collection, user=request.user)
|
||||
return render(request, 'core/collection_form.html', {'form': form, 'collection': collection, 'heading': _('Edit collection')})
|
||||
|
||||
|
||||
@@ -708,7 +733,7 @@ def collection_manage(request, pk):
|
||||
if request.method == 'POST':
|
||||
action = request.POST.get('action')
|
||||
if action in {'add', 'confirm_add'}:
|
||||
item = get_object_or_404(visible_items(request.user), pk=request.POST.get('item_id'), kind=Item.Kind.NOTE)
|
||||
item = get_object_or_404(editable_collection_notes(request.user), pk=request.POST.get('item_id'))
|
||||
if collection_item_is_compatible(collection, item):
|
||||
add_collection_section(collection, item)
|
||||
return redirect(manage_url)
|
||||
|
||||
Reference in New Issue
Block a user