Example #1
0
def get_prioritized(queryset, request):
    # Prefetch related
    queryset = EventSerializer.setup_eager_loading(queryset)

    # Get profile if authenticated
    profile = None
    if request.user.is_authenticated and hasattr(request.user, 'profile'):
        profile = request.user.profile

    # Iterate all events
    for event in queryset:
        event.weight = EventPrioritizer(event, profile).compute().weight

    return sorted(queryset, key=lambda event: (event.weight, event.start_time), reverse=True)
Example #2
0
def get_prioritized(queryset, request):
    now = timezone.now()

    # Prefetch related
    queryset = EventSerializer.setup_eager_loading(queryset)

    # Prefetch followed bodies
    followed_bodies = None
    if request.user.is_authenticated and hasattr(request.user, 'profile'):
        profile = request.user.profile
        followed_bodies = profile.followed_bodies.all()

    # Iterate all events
    for event in queryset:
        event.weight = BASE

        # Get difference in days
        end_time_diff = (event.end_time - now).total_seconds() / 86400
        start_time_diff = (event.start_time - now).total_seconds()  / 86400

        start_time_factor = math.exp((-(start_time_diff / TIME_SD)**2))

        # Apply exponential to and penalise finished events
        if event.end_time < now:
            event.weight -= FINISHED_PENALTY
            end_time_factor = math.exp(-abs(end_time_diff) / TIME_L_END)
            start_time_factor *= end_time_factor

        start_time_points = WEIGHT_START_TIME * start_time_factor
        event.weight += int(start_time_points)

        if followed_bodies:
            body_bonus = 0
            for body in event.bodies.all():
                if body_bonus >= BODY_BONUS_MAX:
                    break
                if body in followed_bodies:
                    body_bonus += int(BODY_FOLLOWING_BONUS + (TIME_DEP_BODY_BONUS * start_time_factor))
            event.weight += body_bonus

    return sorted(queryset, key=lambda event: (-event.weight, event.start_time))
Example #3
0
def get_prioritized(queryset, request):
    now = timezone.now()

    # Prefetch related
    queryset = EventSerializer.setup_eager_loading(queryset)

    # Prefetch followed bodies
    followed_bodies = None
    profile = None
    if request.user.is_authenticated and hasattr(request.user, 'profile'):
        profile = request.user.profile
        followed_bodies = profile.followed_bodies.all()

    # Iterate all events
    for event in queryset:
        event.weight = BASE

        # Get difference in days
        end_time_diff = (event.end_time - now).total_seconds() / 86400
        start_time_diff = (event.start_time - now).total_seconds() / 86400

        start_time_factor = math.exp((-(start_time_diff / TIME_SD)**2))

        # Event Length penalty
        event_length = (event.end_time - event.start_time).total_seconds()
        # factor_b is the number of days as a float
        factor_b = event_length / 86400
        length_penalty = 1 / (1 + TIME_PENALTY_FACTOR * factor_b)
        # Apply exponential to and penalise finished events
        if event.end_time < now:
            event.weight -= FINISHED_PENALTY
            end_time_factor = math.exp(-abs(end_time_diff) / TIME_L_END)
            start_time_factor *= end_time_factor

        start_time_points = WEIGHT_START_TIME * start_time_factor
        event.weight += int(start_time_points)

        # Penalize for not being tagged
        categories_satisfy = []
        categories = []
        for tag in event.user_tags.all():
            if tag.category not in categories:
                categories.append(tag.category)
            if tag.category not in categories_satisfy and tag.match(profile):
                categories_satisfy.append(tag.category)
        event.weight -= int((len(categories) - len(categories_satisfy)) *
                            NOT_TAG_TARGET_PENALTY)

        # Grant bonus to followed bodies
        if followed_bodies:
            body_bonus = 0
            for body in event.bodies.all():
                if body_bonus >= BODY_BONUS_MAX:
                    break
                if body in followed_bodies:
                    body_bonus += int(BODY_FOLLOWING_BONUS +
                                      (TIME_DEP_BODY_BONUS *
                                       start_time_factor))
            event.weight += body_bonus
        # Apply Length Penalty
        event.weight *= length_penalty

    return sorted(queryset,
                  key=lambda event: (event.weight, event.start_time),
                  reverse=True)
Example #4
0
class EventViewSet(viewsets.ModelViewSet):  # pylint: disable=too-many-ancestors
    """Event"""

    queryset = Event.objects.all()
    queryset = EventSerializer.setup_eager_loading(queryset)
    serializer_class = EventFullSerializer

    def get_serializer_context(self):
        return {'request': self.request}

    def retrieve(self, request, pk):
        """Get Event.
        Get by `uuid` or `str_id`"""

        event = self.get_event(pk)
        serialized = EventFullSerializer(event, context={
            'request': request
        }).data

        return Response(serialized)

    def list(self, request):  #pylint: disable=unused-argument
        """List Events.
        List fresh events prioritized for the current user."""

        # Check for date filtered query params
        start = request.GET.get('start')
        end = request.GET.get('end')

        if start is not None and end is not None:
            # Try date-filtered if we have the params
            queryset = get_prioritized(
                self.queryset.filter(start_time__range=(start, end)), request)
        else:
            # Respond with recent events
            queryset = get_fresh_prioritized_events(self.queryset, request)

        serializer = EventSerializer(queryset,
                                     many=True,
                                     context={'request': request})
        data = serializer.data

        return Response({'count': len(data), 'data': data})

    @login_required_ajax
    def create(self, request):
        """Create Event.
        Needs `AddE` permission for each body to be associated."""

        # Prevent events without any body
        if 'bodies_id' not in request.data or not request.data['bodies_id']:
            return forbidden_no_privileges()

        # Check privileges for all bodies
        if all([
                user_has_privilege(request.user.profile, id, 'AddE')
                for id in request.data['bodies_id']
        ]):

            # Fill in ids of venues
            request.data['venue_ids'] = create_unreusable_locations(
                request.data['venue_names'])
            return super().create(request)

        return forbidden_no_privileges()

    @login_required_ajax
    def update(self, request, pk):
        """Update Event.
        Needs BodyRole with `UpdE` for at least one associated body.
        Disassociating bodies from the event requires the `DelE`
        permission and associating needs `AddE`"""

        # Prevent events without any body
        if 'bodies_id' not in request.data or not request.data['bodies_id']:
            return forbidden_no_privileges()

        # Get difference in bodies
        event = self.get_event(pk)
        old_bodies_id = [str(x.id) for x in event.bodies.all()]
        new_bodies_id = request.data['bodies_id']
        added_bodies = diff_set(new_bodies_id, old_bodies_id)
        removed_bodies = diff_set(old_bodies_id, new_bodies_id)

        # Check if user can add events for new bodies
        can_add_events = all([
            user_has_privilege(request.user.profile, id, 'AddE')
            for id in added_bodies
        ])

        # Check if user can remove events for removed
        can_del_events = all([
            user_has_privilege(request.user.profile, id, 'DelE')
            for id in removed_bodies
        ])

        # Check if the user can update event for any of the old bodies
        can_update = any([
            user_has_privilege(request.user.profile, id, 'UpdE')
            for id in old_bodies_id
        ])

        if can_add_events and can_del_events and can_update:
            # Create added unreusable venues, unlink deleted ones
            old_venue_names = [x.name for x in event.venues.all()]
            new_venue_names = request.data['venue_names']
            added_venues = diff_set(new_venue_names, old_venue_names)
            common_venues = list(
                set(old_venue_names).intersection(new_venue_names))

            common_venue_ids = [
                str(x.id) for x in event.venues.filter(name__in=common_venues)
            ]
            added_venue_ids = create_unreusable_locations(added_venues)

            request.data['venue_ids'] = added_venue_ids + common_venue_ids

            return super().update(request, pk)

        return forbidden_no_privileges()

    @login_required_ajax
    def destroy(self, request, pk):
        """Delete Event.
        Needs `DelE` permission for all associated bodies."""

        event = self.get_event(pk)
        if all([
                user_has_privilege(request.user.profile, str(body.id), 'DelE')
                for body in event.bodies.all()
        ]):
            return super().destroy(request, pk)

        return forbidden_no_privileges()

    def get_event(self, pk):
        """Get an event from pk uuid or strid."""
        try:
            UUID(pk, version=4)
            return get_object_or_404(self.queryset, id=pk)
        except ValueError:
            return get_object_or_404(self.queryset, str_id=pk)
Example #5
0
class EventViewSet(viewsets.ModelViewSet):
    """Event"""

    queryset = Event.objects.all()
    queryset = EventSerializer.setup_eager_loading(queryset)
    serializer_class = EventFullSerializer

    def get_serializer_context(self):
        return {'request': self.request}

    def retrieve(self, request, pk):
        """Get Event.
        Get by `uuid` or `str_id`"""

        event = self.get_event(pk)
        serialized = EventFullSerializer(event, context={'request': request}).data

        return Response(serialized)

    def list(self, request):
        """List Events.
        List fresh events prioritized for the current user."""

        # Check for date filtered query params
        start = request.GET.get('start')
        end = request.GET.get('end')

        if start is not None and end is not None:
            # Try date-filtered if we have the params
            queryset = get_prioritized(self.queryset.filter(
                start_time__range=(start, end)), request)
        else:
            # Respond with recent events
            queryset = get_fresh_prioritized_events(self.queryset, request)

        serializer = EventSerializer(queryset, many=True, context={'request': request})
        data = serializer.data

        return Response({'count': len(data), 'data': data})

    @login_required_ajax
    def create(self, request):
        """Create Event.
        Needs `AddE` permission for each body to be associated."""

        # Prevent events without any body
        if 'bodies_id' not in request.data or not request.data['bodies_id']:
            return forbidden_no_privileges()

        # Check privileges for all bodies
        if all([user_has_privilege(request.user.profile, id, 'AddE')
                for id in request.data['bodies_id']]):

            # Fill in ids of venues
            request.data['venue_ids'] = create_unreusable_locations(request.data['venue_names'])
            return super().create(request)

        return forbidden_no_privileges()

    @login_required_ajax
    def update(self, request, pk):
        """Update Event.
        Needs BodyRole with `UpdE` for at least one associated body.
        Disassociating bodies from the event requires the `DelE`
        permission and associating needs `AddE`"""

        # Prevent events without any body
        if 'bodies_id' not in request.data or not request.data['bodies_id']:
            return forbidden_no_privileges()

        # Get the event currently in database
        event = self.get_event(pk)

        # Check if difference in bodies is valid
        if not can_update_bodies(request.data['bodies_id'], event, request.user.profile):
            return forbidden_no_privileges()

        # Create added unreusable venues, unlink deleted ones
        request.data['venue_ids'] = get_update_venue_ids(request.data['venue_names'], event)

        return super().update(request, pk)

    @login_required_ajax
    def destroy(self, request, pk):
        """Delete Event.
        Needs `DelE` permission for all associated bodies."""

        event = self.get_event(pk)
        if all([user_has_privilege(request.user.profile, str(body.id), 'DelE')
                for body in event.bodies.all()]):
            return super().destroy(request, pk)

        return forbidden_no_privileges()

    def get_event(self, pk):
        """Get an event from pk uuid or strid."""
        try:
            UUID(pk, version=4)
            return get_object_or_404(self.queryset, id=pk)
        except ValueError:
            return get_object_or_404(self.queryset, str_id=pk)