예제 #1
0
    def unregister(self, registration, admin_unregistration_reason=''):
        """
        Pulls the registration, and clears relevant fields. Sets unregistration date.
        If the user was in a pool, and not in the waiting list,
        notifies the waiting list that there might be a bump available.
        """
        if self.start_time < timezone.now():
            raise EventHasClosed()

        # Locks unregister so that no user can register before bump is executed.
        pool_id = registration.pool_id
        registration.unregister(
            is_merged=self.is_merged,
            admin_unregistration_reason=admin_unregistration_reason)
        if pool_id:
            if not admin_unregistration_reason and\
                    self.heed_penalties and self.passed_unregistration_deadline:
                if not registration.user.penalties.filter(
                        source_event=self).exists():
                    Penalty.objects.create(
                        user=registration.user,
                        reason=f'Meldte seg av {self.title} for sent.',
                        weight=1,
                        source_event=self)

            with transaction.atomic():
                locked_event = Event.objects.select_for_update().get(
                    pk=self.id)
                locked_pool = locked_event.pools.get(id=pool_id)
                locked_event.check_for_bump_or_rebalance(locked_pool)
                follow_event_item = FollowEvent.objects.filter(
                    follower=registration.user, target=locked_event).first()
                if follow_event_item:
                    follow_event_item.delete()
예제 #2
0
    def register(self, registration):
        """
        Evaluates a pending registration for the event,
        and automatically selects the optimal pool for the registration.

        First checks if there exist any legal pools for the pending registration,
        raises an exception if not.

        If there is only one possible pool, checks if the pool is full and registers for
        the waiting list or the pool accordingly.

        If the event is merged, and it isn't full, joins any pool.
        Otherwise, joins the waiting list.

        If the event isn't merged, checks if the pools that the pending registration can
        possibly join are full or not. If all are full, a registration for
        the waiting list is created. If there's only one pool that isn't full,
        register for it.

        If there's more than one possible pool that isn't full,
        calculates the total amount of users that can join each pool, and selects the most
        exclusive pool. If several pools have the same exclusivity,
        selects the biggest pool of these.

        :param registration: The registration that gets evaluated
        :return: The registration (in the chosen pool)
        """
        user = registration.user
        penalties = 0

        unanswered_surveys = user.unanswered_surveys()
        if len(unanswered_surveys) > 0:
            raise UnansweredSurveyException()

        if self.heed_penalties:
            penalties = user.number_of_penalties()
        current_time = timezone.now()
        if self.registration_close_time < current_time:
            raise EventHasClosed()

        all_pools = self.pools.all()
        possible_pools = self.get_possible_pools(
            user, all_pools=all_pools, is_admitted=registration.is_admitted)
        if not self.is_ready:
            raise EventNotReady()
        if not possible_pools:
            raise ValueError('No available pools')
        if self.get_earliest_registration_time(user, possible_pools,
                                               penalties) > current_time:
            raise ValueError('Not open yet')

        # Make the user follow the event
        FollowEvent.objects.get_or_create(follower=user, target=self)

        if penalties >= 3:
            return registration.add_to_waiting_list()

        # If the event is merged or has only one pool we can skip a lot of logic
        if all_pools.count() == 1:
            return registration.add_to_pool(possible_pools[0])

        if self.is_merged:
            with transaction.atomic():
                locked_event = Event.objects.select_for_update().get(
                    pk=self.id)
                is_full = locked_event.is_full
                if not is_full:
                    return registration.add_direct_to_pool(possible_pools[0])
            return registration.add_to_waiting_list()

        # Calculates which pools that are full or open for registration based on capacity
        full_pools, open_pools = self.calculate_full_pools(possible_pools)

        if not open_pools:
            return registration.add_to_waiting_list()

        if len(open_pools) == 1:
            return registration.add_to_pool(open_pools[0])

        # Returns a list of the pool(s) with the least amount of potential members
        exclusive_pools = self.find_most_exclusive_pools(open_pools)

        if len(exclusive_pools) == 1:
            chosen_pool = exclusive_pools[0]
        else:
            chosen_pool = self.select_highest_capacity(exclusive_pools)

        return registration.add_to_pool(chosen_pool)