Beispiel #1
0
class AddPostStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "add",
        "default_string": "post",
        "detail_string": "post with title '{title}'"
    }

    section = "Forum"
    input_target = Post
    allowable_targets = [Forum]
    settable_classes = ["all_community_models", Forum]
    model_based_validation = (Post, ["title", "content"])

    # Fields
    title = field_utils.CharField(label="Title", required=True)
    content = field_utils.CharField(label="Content", required=True)

    def implement(self, actor, target, action):
        post = Post.objects.create(title=self.title,
                                   content=self.content,
                                   author=actor,
                                   owner=target.get_owner(),
                                   forum=target)
        self.set_default_permissions(actor, post)
        return post
Beispiel #2
0
class FieldIs(FilterCondition):
    unique_name = "field_is"
    descriptive_name = "Field X is value Y"
    field_to_match = field_utils.CharField(label="Field to match", required=True)
    value_to_match = field_utils.CharField(label="Value to match", required=True)
    inverse = field_utils.BooleanField(label="Flip to inverse")

    def __init__(self, field_to_match, value_to_match, inverse):
        self.field_to_match = field_to_match
        self.value_to_match = value_to_match
        self.inverse = inverse

    def validate(self, permission, target):

        field = getattr(permission.change, self.field_to_match)
        if not field:
            return False, f"No field found for '{self.field_to_match}'"

        if not field.transform_to_valid_value(self.value_to_match):
            return False, f"{self.value_to_match} is not a valid value for {self.field_to_match}"

        return True, None

    def check(self, action):
        field = getattr(action.change, self.field_to_match)
        return field.value == self.value_to_match
Beispiel #3
0
class EditPostStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "edit",
        "default_string": "post",
        "preposition": "in"
    }

    section = "Forum"
    context_keys = ["forum", "post"]
    allowable_targets = [Post]
    settable_classes = ["all_community_models", Forum, Post]
    linked_filters = ["CreatorOnly"]
    model_based_validation = (Post, ["title", "content"])

    title = field_utils.CharField(label="Title")
    content = field_utils.CharField(label="Content")

    def get_context_instances(self, action):
        """Returns the forum and the post object."""
        return {"post": action.target, "forum": action.target.forum}

    def validate(self, actor, target):
        if not self.title and not self.content:
            raise ValidationError(
                "Must provide either a new title or new content when editing post"
            )

    def implement(self, actor, target, action):
        target.title = self.title if self.title else target.title
        target.content = self.content if self.content else target.content
        target.save()
        return target
Beispiel #4
0
class EditGroupStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "edit",
        "default_string": "group",
        "preposition": "for"
    }

    section = "Community"
    allowable_targets = [Group]

    name = field_utils.CharField(label="Group name", required=False)
    description = field_utils.CharField(label="Group description",
                                        required=False)

    def validate(self, actor, target):
        if not self.name and not self.description:
            raise ValidationError(
                "Must provide either a new name or a new description")

    def implement(self, actor, target, action):
        if self.description:
            target.group_description = self.description
        if self.name:
            target.name = self.name
        target.save()
        return target
Beispiel #5
0
class AddColumnStateChange(BaseStateChange):
    """State change to add column to a list."""

    descriptive_text = {
        "verb": "add",
        "default_string": "column to list",
        "detail_string": "column '{column_name}' to list"
    }

    section = "List"
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    # Fields
    column_name = field_utils.CharField(label="Name of column", required=True)
    required = field_utils.CharField(label="Is column required")
    default_value = field_utils.CharField(label="Default value of column")

    def validate(self, actor, target):
        target.add_column(**self.get_field_data(with_unset=False))

    def implement(self, actor, target, **kwargs):
        target.add_column(**self.get_field_data(with_unset=False))
        target.save()
        return target
Beispiel #6
0
class AddForumStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "add",
        "default_string": "forum",
        "detail_string": "forum '{name}'",
        "preposition": "on"
    }

    section = "Forum"
    input_target = Forum  # is this vestigial?
    allowable_targets = ["all_community_models"]
    settable_classes = ["all_community_models", Forum]

    # Fields
    name = field_utils.CharField(label="Name of forum", required=True)
    description = field_utils.CharField(label="Forum description",
                                        null_value="")

    def implement(self, actor, target, action):
        forum = Forum.objects.create(name=self.name,
                                     description=self.description,
                                     owner=target.get_owner())
        self.set_default_permissions(actor, forum)
        return forum
Beispiel #7
0
class EditListStateChange(BaseStateChange):
    """State Change to edit an existing list."""

    descriptive_text = {
        "verb": "edit",
        "default_string": "list",
        "detail_string": "list to have name '{name}' and description '{description}'"
    }

    section = "List"
    model_based_validation = ("target", ["name", "description"])
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    # Fields
    name = field_utils.CharField(label="Name")
    description = field_utils.CharField(label="Description")

    def validate(self, actor, target):
        if not self.name and not self.description:
            raise ValidationError("Must supply new name or description when editing List.")

    def implement(self, actor, target, **kwargs):
        target.name = self.name if self.name else target.name
        target.description = self.description if self.description else target.description
        target.save()
        return target
Beispiel #8
0
class EditForumStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "edit",
        "default_string": "forum",
        "preposition": "in"
    }

    section = "Forum"
    allowable_targets = [Forum]
    settable_classes = ["all_community_models", Forum]

    name = field_utils.CharField(label="Name of forum")
    description = field_utils.CharField(label="Forum description")

    def validate(self, actor, target):
        if not self.name and not self.description:
            raise ValidationError(
                "Must provide either a new name or a new description")

    def implement(self, actor, target, action):
        target.name = self.name if self.name else target.name
        target.description = self.description if self.description else target.description
        target.save()
        return target
Beispiel #9
0
class EditDocumentStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "edit",
        "default_string": "document"
    }

    section = "Document"
    model_based_validation = (Document, ["name", "description", "content"])
    allowable_targets = [Document]
    settable_classes = ["all_community_models", Document]

    # Fields
    name = field_utils.CharField(label="Name")
    description = field_utils.CharField(label="Description")
    content = field_utils.CharField(label="Content")

    def validate(self, actor, target):
        if not self.name and not self.description and not self.content:
            raise ValidationError("Must edit name, description or content")

    def implement(self, actor, target, **kwargs):
        target.name = self.name if self.name else target.name
        target.description = self.description if self.description else target.description
        target.content = self.content if self.content else target.content
        target.save()
        return target
Beispiel #10
0
class AddCommentStateChange(BaseStateChange):
    """State Change to add a comment."""

    descriptive_text = {
        "verb": "add",
        "default_string": "comment"
    }

    section = "Comment"
    model_based_validation = (Comment, ["text"])
    context_keys = ["commented_object"]
    linked_filters = ["TargetTypeFilter", "CreatorOfCommentedFilter"]

    # Fields
    text = field_utils.CharField(label="Comment text", required=True)

    @classmethod
    def get_context_instances(cls, action):
        """Returns the commented object by its model name, to handle cases where the referer knows the model type
        vs doesn't know the model type."""
        commented_object = action.target
        model_name = commented_object.__class__.__name__.lower()
        return {"commented_object": commented_object, model_name: commented_object}

    def implement(self, actor, target, **kwargs):

        comment = Comment(text=self.text, commenter=actor)
        comment.commented_object = target
        comment.owner = target.get_owner()
        comment.save()

        self.set_default_permissions(actor, comment)

        return comment
Beispiel #11
0
class ActorIsSameAs(FilterCondition):
    """
    Note: this replaces:
        'self only' (actor is the same as member_pk_list)
        'original creator only' (actor is the same as target.commented_on.creator)
        'commenter only' (actor is the same as target.creator)
    """
    unique_name = "actor_is_same_as"
    descriptive_name = "Actor is the same as"
    field_to_match = field_utils.CharField(label="Field to match", required=True)
    inverse = field_utils.BooleanField(label="Flip to inverse")

    def __init__(self, field_to_match, inverse=False):
        self.field_to_match = field_to_match
        self.inverse = inverse

    def validate(self, permission, target):

        field = self.get_matching_field(self.field_to_match, permission=permission, target=target)
        if not field:
            return False, f"No field found for '{self.field_to_match}'"

        convertible = field.can_convert_to("ActorField")

        if not field:
            return False, f"Field {self.field_to_match} cannot convert to Actor"

        return True

    def check(self, action):
        field = self.get_matching_field(self.field_to_match, action=action)
        if action.actor == field.to_ActorField:
            return True
        return False
Beispiel #12
0
class ContainsText(FilterCondition):
    unique_name = "field_contains_text"
    descriptive_name = "Field contains text"
    field_to_match = field_utils.CharField(label="Field to match", required=True)
    inverse = field_utils.BooleanField(label="Flip to inverse")

    def __init__(self, field_to_match, text, inverse=False):
        self.field_to_match = field_to_match
        self.text = text
        self.inverse = inverse

    def validate(self, permission, target):

        field = self.get_matching_field(self.field_to_match, permission=permission, target=target)
        if not field:
            return False, f"No field {self.field_to_match} on target"

        convertible = field.can_convert_to("CharField")
        if not field:
            return False, f"Field {self.field_to_match} cannot convert to text"

        return True

    def check(self, action):
        field = self.get_matched_field([action, action.target])
        if self.text in field:
            return True
        return False
Beispiel #13
0
class EditCommentStateChange(BaseStateChange):
    """State Change to edit a comment."""

    descriptive_text = {
        "verb": "edit",
        "default_string": "comment"
    }

    section = "Comment"
    context_keys = ["comment", "commented_object"]
    model_based_validation = (Comment, ["text"])
    linked_filters = ["CommenterFilter", "CreatorOfCommentedFilter"]
    allowable_targets = [Comment]
    settable_classes = ["all_models"]

    # Fields
    text = field_utils.CharField(label="Comment text", required=True)

    @classmethod
    def get_context_instances(cls, action):
        """Returns the comment and the commented object. Also returns the commented object by its model
        name, to handle cases where the referer knows the model type vs doesn't know the model type."""
        comment = action.target
        commented_object = action.target.commented_object
        model_name = commented_object.__class__.__name__.lower()
        return {"comment": comment, "commented_object": commented_object, model_name: commented_object}

    def implement(self, actor, target, **kwargs):
        target.text = self.text
        target.save()
        return target
Beispiel #14
0
class EditTemplateStateChange(BaseStateChange):
    """State change to edit a template."""

    descriptive_text = {
        "verb":
        "edit",
        "default_string":
        "template",
        "detail_string":
        "template field {field_name} to new value {new_field_data}"
    }

    allowable_targets = [TemplateModel]
    settable_classes = ["all_models"]

    template_object_id = field_utils.IntegerField(
        label="ID of Template to edit", required=True)
    field_name = field_utils.CharField(label="Field to edit", required=True)
    new_field_data = field_utils.DictField(label="Data to edit", required=True)

    def validate(self, actor, target):
        result = target.data.update_field(self.template_object_id,
                                          self.field_name, self.new_field_data)
        if result.__class__.__name__ == "ValidationError":
            raise result

    def implement(self, actor, target, **kwargs):

        target.data.update_field(self.template_object_id, self.field_name,
                                 self.new_field_data)
        target.save()

        return target
Beispiel #15
0
class RespondConsensusStateChange(BaseStateChange):
    """State change for responding to a consensus condition"""

    descriptive_text = {
        "verb": "respond",
        "default_string": "",
        "detail_string": "with {response}",
        "preposition": ""
    }

    section = "Consensus"
    allowable_targets = [ConsensusCondition]

    response = field_utils.CharField(label="Response", required=True)

    def validate(self, actor, target):
        """Checks that the actor is a participant."""
        if self.response not in target.response_choices:
            raise ValidationError(
                f"Response must be one of {', '.join(target.response_choices)}, not {self.response}")

    def implement(self, actor, target, **kwargs):
        target.add_response(actor, self.response)
        target.save()
        return self.response
Beispiel #16
0
class AddVoteStateChange(BaseStateChange):
    """State change for adding a vote."""

    descriptive_text = {
        "verb": "vote",
        "default_string": "",
        "detail_string": "{vote}"
    }

    section = "Vote"
    allowable_targets = [VoteCondition]

    vote = field_utils.CharField(label="Vote", required=True)

    def validate(self, actor, target):
        """
        To validate the vote, we need to check that:
        a) the voter hasn't voted before
        b) if the vote is abstain, abstentions are allowed
        """

        if self.vote not in ["yea", "nay", "abstain"]:
            raise ValidationError(f"Vote type must be 'yea', 'nay' or 'abstain', not {self.vote}")
        if target.has_voted(actor):
            raise ValidationError("Actor may only vote once")
        if not target.allow_abstain and self.vote == "abstain":
            raise ValidationError("Actor abstained but this vote does not allow abstentions.")

    def implement(self, actor, target, **kwargs):
        target.add_vote(self.vote)
        target.add_vote_record(actor)
        target.save()
        return True
Beispiel #17
0
class RemoveConditionStateChange(BaseStateChange):
    """State change to remove condition from Community."""

    descriptive_text = {
        "verb": "remove",
        "default_string": "condition",
        "detail_string": "condition with {element_id}"
    }

    is_foundational = True
    section = "Leadership"
    allowable_targets = ["all_community_models", PermissionsItem]

    element_id = field_utils.IntegerField(label="Element ID to remove")
    leadership_type = field_utils.CharField(label="Leadership type to remove condition from")

    def is_conditionally_foundational(self, action):
        """Edit condition is foundational when the condition is owner/governor."""
        return self.leadership_type in ["owner", "governor"]

    def validate(self, actor, target):
        if hasattr(target, "is_community") and target.is_community and not self.leadership_type:
            raise ValidationError("leadership_type cannot be None")

    def implement(self, actor, target, **kwargs):

        attr_name = "condition" if not self.leadership_type else self.leadership_type + "_condition"
        manager = getattr(target, attr_name)

        if self.element_id:
            manager.remove_condition(self.element_id)
            manager.save()
            return manager
        else:
            manager.delete()
Beispiel #18
0
class FieldMatchesFilter(Filter):
    descriptive_name = "a field matches a value"
    configured_name = "{field_to_match} matches '{value_to_match}'"

    field_to_match = field_utils.CharField(label="Field to match", required=True)
    value_to_match = field_utils.CharField(label="Value to match", required=True)

    # TODO: for now we can only match change object fields, probably should be more flexible - use crawl objects?

    def validate(self, permission):
        change_obj = permission.get_state_change_object()
        if not hasattr(change_obj, self.field_to_match):
            return False, f"No field '{self.field_to_match}' on this permission"
        return True, None

    def check(self, *, action, **kwargs):
        """The contents of the action field should equal the custom text."""
        field_value = getattr(action.change, self.field_to_match)
        return field_value == self.value_to_match, "field does not match"
Beispiel #19
0
class EditConditionStateChange(BaseStateChange):
    """State change to add condition to permission or leadership role."""

    descriptive_text = {
        "verb": "edit",
        "default_string": "condition",
        "detail_string": "condition with {element_id}"
    }

    section = "Permissions"
    allowable_targets = ["all_community_models", PermissionsItem]

    element_id = field_utils.IntegerField(label="Element ID", required=True)
    condition_data = field_utils.DictField(label="New condition data", null_value=dict)
    permission_data = field_utils.DictField(label="Data for permissions set on condition", null_value=list)
    leadership_type = field_utils.CharField(label="Leadership type to set condition on")

    def is_conditionally_foundational(self, action):
        """Edit condition is foundational when the condition is owner/governor."""
        return self.leadership_type in ["owner", "governor"]

    def validate(self, actor, target):

        if hasattr(target, "is_community") and target.is_community:

            if not self.leadership_type:
                raise ValidationError("leadership_type cannot be None")

            if self.leadership_type not in ["owner", "governor"]:
                raise ValidationError("leadership_type must be 'owner' or 'governor'")

        if self.leadership_type:
            condition_manager = getattr(target, self.leadership_type + "_condition")
        else:
            condition_manager = target.condition

        element = condition_manager.get_condition_data(self.element_id)
        is_valid, message = validate_condition(
            element.condition_type, self.condition_data, self.permission_data, target)
        if not is_valid:
            raise ValidationError(message)

    def implement(self, actor, target, **kwargs):

        attr_name = "condition" if not self.leadership_type else self.leadership_type + "_condition"
        manager = getattr(target, attr_name)
        data = {"condition_data": self.condition_data, "permission_data": self.permission_data}
        manager.edit_condition(element_id=self.element_id, data_for_condition=data)
        manager.save()

        return manager
Beispiel #20
0
class FieldContainsFilter(Filter):
    descriptive_name = "a field contains specific text"
    configured_name = "{field_to_match} {verb} '{value_to_match}'"

    field_to_match = field_utils.CharField(label="Field to look in", required=True)
    value_to_match = field_utils.CharField(label="Text to search for", required=True)
    inverse = field_utils.BooleanField(label="Reverse (only allowed if it does NOT contain above text)", default=False)

    # TODO: for now we can only match change object fields, probably should be more flexible - use crawl objects?
    # TODO: should either restrict this to text fields or find a coherent way of translating non-text fields to text

    def does_not_contain(self):
        if isinstance(self.inverse, bool):
            return self.inverse
        return False

    def validate(self, permission):
        change_obj = permission.get_state_change_object()
        if not hasattr(change_obj, self.field_to_match):
            return False, f"No field '{self.field_to_match}' on this permission"
        return True, None

    def check(self, *, action, **kwargs):
        """The contents of the action field should equal the custom text."""
        field_value = getattr(action.change, self.field_to_match)
        if self.does_not_contain:
            failure_msg = f"field '{self.field_to_match}' contains '{self.value_to_match.lower()}'"
            return self.value_to_match.lower() not in field_value.lower(), failure_msg
        failure_msg = f"field '{self.field_to_match}' does not contain '{self.value_to_match.lower()}'"
        return self.value_to_match.lower() in field_value.lower(), failure_msg

    def get_configured_name(self):
        if hasattr(self, "configured_name"):
            text_dict = self.get_input_field_values()
            text_dict["verb"] = "does not contain" if self.does_not_contain() else "contains"
            return self.configured_name.format(**text_dict)
        return self.get_descriptive_name()
Beispiel #21
0
class AddListStateChange(BaseStateChange):
    """State Change to create a list in a community (or other target)."""

    descriptive_text = {
        "verb": "add",
        "default_string": "list",
        "detail_string": "list with {name}"
    }

    section = "List"
    model_based_validation = (SimpleList, ["name", "description"])
    allowable_targets = ["all_community_models"]

    # Fields
    name = field_utils.CharField(label="Name", required=True)
    description = field_utils.CharField(label="Description")

    def implement(self, actor, target, **kwargs):
        simple_list = SimpleList(name=self.name, owner=target.get_owner(), creator=actor)
        if self.description:
            simple_list.description = self.description
        simple_list.save()
        self.set_default_permissions(actor, simple_list)
        return simple_list
Beispiel #22
0
class EditRowStateChange(BaseStateChange):
    """State Change to edit a row in a list."""

    descriptive_text = {
        "verb": "edit",
        "default_string": "row in list",
        "detail_string": "row with ID {unique_id} to have new content {row_content}"
    }

    section = "List"
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    row_content = field_utils.CharField(label="Content of row", required=True)
    unique_id = field_utils.CharField(label="Unique ID of row", required=True)

    def validate(self, actor, target):
        target.edit_row(self.row_content, self.unique_id)
        target.refresh_from_db()

    def implement(self, actor, target, **kwargs):
        target.edit_row(self.row_content, self.unique_id)
        target.save()
        return target
Beispiel #23
0
class CreateDocumentStateChange(BaseStateChange):

    descriptive_text = {
        "verb": "add",
        "default_string": "document",
        "detail_string": "document with name '{name}'"
    }

    section = "Document"
    model_based_validation = (Document, ["name", "description", "content"])
    allowable_targets = ["all_community_models"]

    # Fields
    name = field_utils.CharField(label="Name", required=True)
    description = field_utils.CharField(label="Description")
    content = field_utils.CharField(label="Content")

    def implement(self, actor, target, **kwargs):
        doc = Document(name=self.name, owner=target.get_owner(), creator=actor)
        doc.description = self.description if self.description else doc.description
        doc.content = self.content if self.content else doc.content
        doc.save()
        self.set_default_permissions(actor, doc)
        return doc
Beispiel #24
0
class ChangeNameStateChange(BaseStateChange):
    """State change to change name of Community."""

    descriptive_text = {
        "verb": "change",
        "default_string": "name of community",
        "detail_string": "nameof community to {name}",
        "preposition": "for"
    }

    section = "Community"
    model_based_validation = ("target", ["name"])
    allowable_targets = ["all_community_models"]

    name = field_utils.CharField(label="New name", required=True)

    def implement(self, actor, target, **kwargs):
        target.name = self.name
        target.save()
        return target
Beispiel #25
0
class DeleteRowStateChange(BaseStateChange):
    """State Change to delete a row in a list."""

    descriptive_text = {
        "verb": "delete",
        "default_string": "row in list",
        "detail_string": "row with id {unique_id}"
    }

    section = "List"
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    # Fields
    unique_id = field_utils.CharField(label="Unique ID of row to delete", required=True)

    def implement(self, actor, target, **kwargs):
        target.delete_row(self.unique_id)
        target.save()
        return target
Beispiel #26
0
class DeleteColumnStateChange(BaseStateChange):
    descriptive_text = {
        "verb": "delete",
        "default_string": "column from list",
        "detail_string": "column '{column_name}' from list"
    }

    section = "List"
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    # Fields
    column_name = field_utils.CharField(label="Name of column", required=True)

    def validate(self, actor, target):
        target.delete_column(self.column_name)

    def implement(self, actor, target, **kwargs):
        target.delete_column(self.column_name)
        target.save()
        return target
Beispiel #27
0
class AddRowStateChange(BaseStateChange):
    """State Change to add a row to a list."""

    descriptive_text = {
        "verb": "add",
        "default_string": "row to list",
        "detail_string": "row with content {row_content} to list"
    }

    section = "List"
    allowable_targets = [SimpleList]
    settable_classes = ["all_community_models", SimpleList]

    # Fields
    row_content = field_utils.CharField(label="Content of row", required=True)

    def validate(self, actor, target):
        target.add_row(self.row_content)
        target.refresh_from_db()

    def implement(self, actor, target, **kwargs):
        unique_id = target.add_row(self.row_content)
        target.save()
        return (target, unique_id)
Beispiel #28
0
class AddPermissionStateChange(BaseStateChange):
    """State change to add a permission to something."""

    descriptive_text = {  # note that description_present_tense and past tense are overridden below
        "verb": "add",
        "default_string": "permission"
    }

    section = "Permissions"
    model_based_validation = (PermissionsItem,
                              ["change_type", "anyone", "inverse"])

    change_type = field_utils.CharField(
        label="Type of action the permission covers", required=True)
    actors = field_utils.ActorListField(
        label="Actors who have this permission", null_value=list)
    roles = field_utils.RoleListField(label="Roles who have this permission",
                                      null_value=list)
    anyone = field_utils.BooleanField(label="Everyone has the permission",
                                      null_value=False)
    inverse = field_utils.BooleanField(
        label="Do the inverse of this permission", null_value=False)
    condition_data = field_utils.CharField(
        label="Condition for this permission")

    def description_present_tense(self):
        return f"add permission '{get_verb_given_permission_type(self.change_type)}'"

    def description_past_tense(self):
        return f"added permission '{get_verb_given_permission_type(self.change_type)}'"

    def is_conditionally_foundational(self, action):
        """Some state changes are only foundational in certain conditions. Those state changes override this
        method to apply logic and determine whether a specific instance is foundational or not."""
        from concord.utils.lookups import get_state_change_object
        change_object = get_state_change_object(self.change_type)
        return action.change.is_foundational

    def validate(self, actor, target):

        permission = get_state_change_object(self.change_type)

        # check that target is a valid class for the permission to be set on
        if target.__class__ not in permission.get_settable_classes():
            settable_classes_str = ", ".join(
                [str(option) for option in permission.get_settable_classes()])
            raise ValidationError(
                f"This kind of permission cannot be set on target {target} of class "
                + f"{target.__class__}, must be {settable_classes_str}")

        # validate condition data
        if self.condition_data:
            for condition in self.condition_data:
                is_valid, message = validate_condition(
                    condition["condition_type"], condition["condition_data"],
                    condition["permission_data"], target)
                if not is_valid:
                    raise ValidationError(message)

    def implement(self, actor, target, **kwargs):

        permission = PermissionsItem()
        permission.set_fields(owner=target.get_owner(),
                              permitted_object=target,
                              anyone=self.anyone,
                              change_type=self.change_type,
                              inverse=self.inverse,
                              actors=self.actors,
                              roles=self.roles)
        permission.save()

        # if condition, add and save
        if self.condition_data:

            # create initial manager
            owner = permission.get_owner()
            manager = ConditionManager.objects.create(owner=owner,
                                                      community=owner.pk,
                                                      set_on="permission")
            permission.condition = manager

            # add conditions
            for condition in self.condition_data:
                data = {
                    "condition_type": condition["condition_type"],
                    "condition_data": condition["condition_data"],
                    "permission_data": condition["permission_data"]
                }
                manager.add_condition(data_for_condition=data)
                manager.save()

        return permission
Beispiel #29
0
class AddConditionStateChange(BaseStateChange):
    """State change to add condition to permission or leadership role."""

    descriptive_text = {
        "verb": "add",
        "default_string": "condition",
        "detail_string": "condition {condition_type}"
    }

    section = "Permissions"
    allowable_targets = ["all_community_models", PermissionsItem]

    condition_type = field_utils.CharField(label="Type of condition to add", required=True)
    condition_data = field_utils.DictField(label="Data for condition", null_value=dict)
    permission_data = field_utils.DictField(label="Data for permissions set on condition", null_value=list)
    leadership_type = field_utils.CharField(label="Type of leadership condition is set on")

    def is_conditionally_foundational(self, action):
        """Edit condition is foundational when the condition is owner/governor."""
        return self.leadership_type in ["owner", "governor"]

    def validate(self, actor, target):

        if not self.condition_type:
            raise ValidationError("condition_type cannont be None")

        if not Client().Conditional.is_valid_condition_type(self.condition_type):
            raise ValidationError(f"condition_type must be a valid condition class not {self.condition_type}")

        if hasattr(target, "is_community") and target.is_community:

            if not self.leadership_type:
                raise ValidationError("leadership_type cannot be None")

            if self.leadership_type not in ["owner", "governor"]:
                raise ValidationError("leadership_type must be 'owner' or 'governor'")

        is_valid, message = validate_condition(self.condition_type, self.condition_data, self.permission_data, target)
        if not is_valid:
            raise ValidationError(message)

    def implement(self, actor, target, **kwargs):

        attr_name = "condition" if not self.leadership_type else self.leadership_type + "_condition"
        manager = getattr(target, attr_name)

        if not manager:
            from concord.conditionals.models import ConditionManager
            owner = target.get_owner()
            set_on = self.leadership_type if self.leadership_type else "permission"
            manager = ConditionManager.objects.create(owner=owner, community=owner.pk, set_on=set_on)
            setattr(target, attr_name, manager)
            target.save()

        condition_dict = self.condition_data if self.condition_data else {}
        data = {"condition_type": self.condition_type, "condition_data": condition_dict,
                "permission_data": self.permission_data}
        manager.add_condition(data_for_condition=data)
        manager.save()

        return manager