123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- from django import forms
- from django.core.exceptions import PermissionDenied
- from django.http import Http404
- from django.utils.translation import gettext_lazy as _
- from ...acl import algebra
- from ...acl.decorators import return_boolean
- from ...acl.models import Role
- from ...admin.forms import YesNoSwitch
- from ...categories import PRIVATE_THREADS_ROOT_NAME
- from ...categories.models import Category
- from ..models import Thread
- __all__ = [
- "allow_use_private_threads",
- "can_use_private_threads",
- "allow_see_private_thread",
- "can_see_private_thread",
- "allow_change_owner",
- "can_change_owner",
- "allow_add_participants",
- "can_add_participants",
- "allow_remove_participant",
- "can_remove_participant",
- "allow_add_participant",
- "can_add_participant",
- "allow_message_user",
- "can_message_user",
- ]
- class PermissionsForm(forms.Form):
- legend = _("Private threads")
- can_use_private_threads = YesNoSwitch(label=_("Can use private threads"))
- can_start_private_threads = YesNoSwitch(label=_("Can start private threads"))
- max_private_thread_participants = forms.IntegerField(
- label=_("Max number of users invited to private thread"),
- help_text=_("Enter 0 to don't limit number of participants."),
- initial=3,
- min_value=0,
- )
- can_add_everyone_to_private_threads = YesNoSwitch(
- label=_("Can add everyone to threads"),
- help_text=_(
- "Allows user to add users that are blocking him to private threads."
- ),
- )
- can_report_private_threads = YesNoSwitch(
- label=_("Can report private threads"),
- help_text=_(
- "Allows user to report private threads they are "
- "participating in, making them accessible to moderators."
- ),
- )
- can_moderate_private_threads = YesNoSwitch(
- label=_("Can moderate private threads"),
- help_text=_(
- "Allows user to read, reply, edit and delete content "
- "in reported private threads."
- ),
- )
- def change_permissions_form(role):
- if isinstance(role, Role) and role.special_role != "anonymous":
- return PermissionsForm
- else:
- return None
- def build_acl(acl, roles, key_name):
- new_acl = {
- "can_use_private_threads": 0,
- "can_start_private_threads": 0,
- "max_private_thread_participants": 3,
- "can_add_everyone_to_private_threads": 0,
- "can_report_private_threads": 0,
- "can_moderate_private_threads": 0,
- }
- new_acl.update(acl)
- algebra.sum_acls(
- new_acl,
- roles=roles,
- key=key_name,
- can_use_private_threads=algebra.greater,
- can_start_private_threads=algebra.greater,
- max_private_thread_participants=algebra.greater_or_zero,
- can_add_everyone_to_private_threads=algebra.greater,
- can_report_private_threads=algebra.greater,
- can_moderate_private_threads=algebra.greater,
- )
- if not new_acl["can_use_private_threads"]:
- new_acl["can_start_private_threads"] = 0
- return new_acl
- private_category = Category.objects.private_threads()
- new_acl["visible_categories"].append(private_category.pk)
- new_acl["browseable_categories"].append(private_category.pk)
- if new_acl["can_moderate_private_threads"]:
- new_acl["can_see_reports"].append(private_category.pk)
- category_acl = {
- "can_see": 1,
- "can_browse": 1,
- "can_see_all_threads": 1,
- "can_see_own_threads": 0,
- "can_start_threads": new_acl["can_start_private_threads"],
- "can_reply_threads": 1,
- "can_edit_threads": 1,
- "can_edit_posts": 1,
- "can_hide_own_threads": 0,
- "can_hide_own_posts": 1,
- "thread_edit_time": 0,
- "post_edit_time": 0,
- "can_hide_threads": 0,
- "can_hide_posts": 0,
- "can_protect_posts": 0,
- "can_move_posts": 0,
- "can_merge_posts": 0,
- "can_pin_threads": 0,
- "can_close_threads": 0,
- "can_move_threads": 0,
- "can_merge_threads": 0,
- "can_approve_content": 0,
- "can_report_content": new_acl["can_report_private_threads"],
- "can_see_reports": 0,
- "can_see_posts_likes": 0,
- "can_like_posts": 0,
- "can_hide_events": 0,
- }
- if new_acl["can_moderate_private_threads"]:
- category_acl.update(
- {
- "can_edit_threads": 2,
- "can_edit_posts": 2,
- "can_hide_threads": 2,
- "can_hide_posts": 2,
- "can_protect_posts": 1,
- "can_merge_posts": 1,
- "can_see_reports": 1,
- "can_close_threads": 1,
- "can_hide_events": 2,
- }
- )
- new_acl["categories"][private_category.pk] = category_acl
- return new_acl
- def add_acl_to_thread(user_acl, thread):
- if thread.thread_type.root_name != PRIVATE_THREADS_ROOT_NAME:
- return
- if not hasattr(thread, "participant"):
- thread.participants_list = []
- thread.participant = None
- thread.acl.update(
- {
- "can_start_poll": False,
- "can_change_owner": can_change_owner(user_acl, thread),
- "can_add_participants": can_add_participants(user_acl, thread),
- }
- )
- def register_with(registry):
- registry.acl_annotator(Thread, add_acl_to_thread)
- def allow_use_private_threads(user_acl):
- if user_acl["is_anonymous"]:
- raise PermissionDenied(_("You have to sign in to use private threads."))
- if not user_acl["can_use_private_threads"]:
- raise PermissionDenied(_("You can't use private threads."))
- can_use_private_threads = return_boolean(allow_use_private_threads)
- def allow_see_private_thread(user_acl, target):
- if user_acl["can_moderate_private_threads"]:
- can_see_reported = target.has_reported_posts
- else:
- can_see_reported = False
- can_see_participating = user_acl["user_id"] in [
- p.user_id for p in target.participants_list
- ]
- if not (can_see_participating or can_see_reported):
- raise Http404()
- can_see_private_thread = return_boolean(allow_see_private_thread)
- def allow_change_owner(user_acl, target):
- is_moderator = user_acl["can_moderate_private_threads"]
- is_owner = target.participant and target.participant.is_owner
- if not (is_owner or is_moderator):
- raise PermissionDenied(
- _("Only thread owner and moderators can change threads owners.")
- )
- if not is_moderator and target.is_closed:
- raise PermissionDenied(_("Only moderators can change closed threads owners."))
- can_change_owner = return_boolean(allow_change_owner)
- def allow_add_participants(user_acl, target):
- is_moderator = user_acl["can_moderate_private_threads"]
- if not is_moderator:
- if not target.participant or not target.participant.is_owner:
- raise PermissionDenied(
- _("You have to be thread owner to add new participants to it.")
- )
- if target.is_closed:
- raise PermissionDenied(
- _("Only moderators can add participants to closed threads.")
- )
- max_participants = user_acl["max_private_thread_participants"]
- current_participants = len(target.participants_list) - 1
- if current_participants >= max_participants:
- raise PermissionDenied(_("You can't add any more new users to this thread."))
- can_add_participants = return_boolean(allow_add_participants)
- def allow_remove_participant(user_acl, thread, target):
- if user_acl["can_moderate_private_threads"]:
- return
- if user_acl["user_id"] == target.id:
- return # we can always remove ourselves
- if thread.is_closed:
- raise PermissionDenied(
- _("Only moderators can remove participants from closed threads.")
- )
- if not thread.participant or not thread.participant.is_owner:
- raise PermissionDenied(
- _("You have to be thread owner to remove participants from it.")
- )
- can_remove_participant = return_boolean(allow_remove_participant)
- def allow_add_participant(user_acl, target, target_acl):
- message_format = {"user": target.username}
- if not can_use_private_threads(target_acl):
- raise PermissionDenied(
- _("%(user)s can't participate in private threads.") % message_format
- )
- if user_acl["can_add_everyone_to_private_threads"]:
- return
- if user_acl["can_be_blocked"] and target.is_blocking(user_acl["user_id"]):
- raise PermissionDenied(_("%(user)s is blocking you.") % message_format)
- if target.can_be_messaged_by_nobody:
- raise PermissionDenied(
- _("%(user)s is not allowing invitations to private threads.")
- % message_format
- )
- if target.can_be_messaged_by_followed and not target.is_following(
- user_acl["user_id"]
- ):
- message = _("%(user)s limits invitations to private threads to followed users.")
- raise PermissionDenied(message % message_format)
- can_add_participant = return_boolean(allow_add_participant)
- def allow_message_user(user_acl, target, target_acl):
- allow_use_private_threads(user_acl)
- allow_add_participant(user_acl, target, target_acl)
- can_message_user = return_boolean(allow_message_user)
|