Esempio n. 1
0
def return_queryset_if_user_has_permissions(queryset,
                                            user,
                                            *models,
                                            customer_queryset=None):
    """
    Checks whether the user has permissions to access the queryset.

    1. If the passed queryset is falsy, we return None.
    2. If the user making the request is a customer, the elements on the
        queryset belonging to it are returned.
    4. If the user is not a customer, but the user has permissions to view
        the necessary models, the whole queryset is returned.
    5. If the user has no permissions to view it, an error is raised.

    :param queryset: Django QuerySet being accessed
    :param user: the user from the current request / session
    :param models: Django models that user has to have permissions to
    :param customer_queryset: [Optional] If the customer property is nested on the model,
    a custom filtered queryset can be passed
    :return: None | Django QuerySet | Exception raised
    """
    from users.utils import is_customer, user_has_view_permission

    if is_customer(user):
        if customer_queryset:
            return customer_queryset
        return queryset.filter(customer__user=user)

    if user_has_view_permission(*models)(user):
        return queryset

    raise VenepaikkaGraphQLError(
        _("You do not have permission to perform this action."))
Esempio n. 2
0
def return_node_if_user_has_permissions(node, user, *models):
    """
    Checks whether the user has permissions to access this node / model.

    1. If the passed node is falsy, we return None.
    2. Otherwise, try to get the user this node belongs to (get_node_user)
    3. If the node belongs to the user making the request,
       the node / model is returned.
    4. If the node does not belong to the user, but the user has
       permissions to view the necessary models, the node / model
       is still returned.
    5. If the node does not belong to the user and the user has no
       permissions to view it, an error is raised.

    :param node: Graphene Node or Django Model being accessed
    :param user: the user from the current request / session
    :param models: Django models that user has to have permissions to
    :return: None | Django Model or Graphene Node | Exception raised
    """
    from users.utils import user_has_view_permission

    if not node:
        return None

    node_user = get_node_user(node)

    if (node_user
            and node_user == user) or user_has_view_permission(*models)(user):
        return node
    else:
        raise VenepaikkaGraphQLError(
            _("You do not have permission to perform this action."))
Esempio n. 3
0
    def get_node(cls, info, id):
        node = super().get_node(info, id)
        user = info.context.user
        # The BerthSwitchOffer node does not have a customer, so it has to be retrieved
        # from the node.customer and cannot use return_node_if_user_has_permissions

        if user_has_view_permission(
                BerthSwitchOffer, BerthLease, BerthApplication)(user) or (
                    node.lease.customer
                    and hasattr(node.lease.customer, "user")
                    and node.lease.customer.user == user):
            return node

        raise PermissionError(
            _("You do not have permission to perform this action."))
Esempio n. 4
0
def resolve_piers(info, **kwargs):
    min_width = kwargs.get("min_berth_width")
    min_length = kwargs.get("min_berth_length")
    application_global_id = kwargs.get("for_application")
    harbor_id = kwargs.get("harbor_id")

    # Filter out piers with no berths that fit the
    # passed dimensions only if the dimensions were given.
    # Otherwise, return the whole list of piers.
    has_dimensions_filter = min_width or min_length

    if has_dimensions_filter and application_global_id:
        raise VenepaikkaGraphQLError(
            _("You cannot filter by dimension (width, length) and application a the same time."
              ))

    if application_global_id:
        user = info.context.user
        if (user and user.is_authenticated
                and user_has_view_permission(BerthApplication)(user)):
            application = get_node_from_global_id(
                info, application_global_id, only_type=BerthApplicationNode)

            min_width = application.boat_width
            # NOTE: not setting min_length here on purpose.
            # See VEN-1251: berths that are too short need to be shown in the UI
        else:
            raise VenepaikkaGraphQLError(
                _("You do not have permission to perform this action"))

    if harbor_id:
        query = Pier.objects.filter(harbor_id=harbor_id)
    else:
        query = Pier.objects.all()

    suitable_berth_types = BerthType.objects.all()
    if min_width:
        suitable_berth_types = suitable_berth_types.filter(
            width__gte=min_width)
    if min_length:
        suitable_berth_types = suitable_berth_types.filter(
            length__gte=min_length)

    berth_queryset = Berth.objects.select_related("berth_type").filter(
        berth_type__in=suitable_berth_types)

    query = query.prefetch_related(
        Prefetch("berths", queryset=berth_queryset),
        "suitable_boat_types",
        "harbor__translations",
        "harbor__availability_level__translations",
        "harbor__municipality__translations",
    ).select_related("harbor", "harbor__availability_level",
                     "harbor__municipality")

    if has_dimensions_filter:
        dimensions_filter = Q()
        if min_width:
            dimensions_filter &= Q(berths__berth_type__width__gte=min_width)
        if min_length:
            dimensions_filter &= Q(berths__berth_type__length__gte=min_length)

        query = query.annotate(
            berth_count=Count("berths", filter=dimensions_filter)).filter(
                berth_count__gt=0)

    return query
class UpdateBerthApplication(graphene.ClientIDMutation):
    class Input(UpdateBerthApplicationInput):
        pass

    berth_application = graphene.Field(BerthApplicationNode)

    @classmethod
    def validate_application_status(cls, application, info, input):
        if application.status != ApplicationStatus.PENDING:
            if is_customer(info.context.user):
                raise VenepaikkaGraphQLError(
                    _("Cannot modify the application once it has been processed"
                      ))

            # If the input receives explicitly customerId: None
            if "customer_id" in input and input.get("customer_id") is None:
                raise VenepaikkaGraphQLError(
                    _("Customer cannot be disconnected from processed applications"
                      ))

    def get_nodes_to_check(info, **input):
        application = get_node_from_global_id(info,
                                              input.get("id"),
                                              only_type=BerthApplicationNode,
                                              nullable=True)
        return [application]

    @classmethod
    @check_user_is_authorised(
        get_nodes_to_check=get_nodes_to_check,
        model_checks=[
            user_has_view_permission(CustomerProfile, BerthLease),
            user_has_change_permission(BerthApplication),
        ],
    )
    @transaction.atomic
    def mutate_and_get_payload(cls, root, info, **input):
        from customers.schema import ProfileNode

        application = get_node_from_global_id(info,
                                              input.pop("id"),
                                              only_type=BerthApplicationNode)

        cls.validate_application_status(application, info, input)

        # This allows for getting explicit None values
        if "customer_id" in input:
            customer_id = input.pop("customer_id", None)

            if is_customer(info.context.user):
                raise VenepaikkaGraphQLError(
                    _("A customer cannot modify the customer connected to the application"
                      ))

            input["customer"] = get_node_from_global_id(info,
                                                        customer_id,
                                                        only_type=ProfileNode,
                                                        nullable=True)

        if remove_choices := input.pop("remove_choices", []):
            for choice_id in remove_choices:
                try:
                    choice = HarborChoice.objects.get(id=from_global_id(
                        choice_id, node_type=HarborChoiceType))
                    choice.delete()
                except HarborChoice.DoesNotExist:
                    pass

        if add_choices := input.pop("add_choices", []):
            for choice in add_choices:
                HarborChoice.objects.get_or_create(
                    harbor_id=from_global_id(choice.get("harbor_id")),
                    priority=choice.get("priority"),
                    application=application,
                )