Ejemplo n.º 1
0
    def speak(self, request, pk=None):
        """
        Special view endpoint to begin and end speech of speakers. Send PUT
        {'speaker': <speaker_id>} to begin speech. Omit data to begin speech of
        the next speaker. Send DELETE to end speech of current speaker.
        """
        # Retrieve list_of_speakers.
        list_of_speakers = self.get_object()

        if request.method == "PUT":
            # Retrieve speaker_id
            speaker_id = request.data.get("speaker")
            if speaker_id is None:
                speaker = list_of_speakers.get_next_speaker()
                if speaker is None:
                    raise ValidationError(
                        {"detail": "The list of speakers is empty."})
            else:
                try:
                    speaker = Speaker.objects.get(pk=int(speaker_id))
                except (ValueError, Speaker.DoesNotExist):
                    raise ValidationError(
                        {"detail": "Speaker does not exist."})
            speaker.begin_speech()
            message = "User is now speaking."

        else:
            # request.method == 'DELETE'
            try:
                # We assume that there aren't multiple entries because this
                # is forbidden by the Model's begin_speech method. We assume that
                # there is only one speaker instance or none.
                current_speaker = (Speaker.objects.filter(
                    list_of_speakers=list_of_speakers,
                    end_time=None).exclude(begin_time=None).get())
            except Speaker.DoesNotExist:
                raise ValidationError({
                    "detail":
                    "There is no one speaking at the moment according to {0}.",
                    "args": [list_of_speakers],
                })
            current_speaker.end_speech()
            message = "The speech is finished now."

        # Initiate response.
        return Response({"detail": message})
Ejemplo n.º 2
0
    def stop(self, request, pk):
        poll = self.get_object()
        # Analog polls could not be stopped; they are stopped when
        # the results are entered.
        if poll.type == BasePoll.TYPE_ANALOG:
            raise ValidationError(
                {"detail": "Analog polls can not be stopped. Please enter votes."}
            )

        if poll.state != BasePoll.STATE_STARTED:
            raise ValidationError({"detail": "Wrong poll state"})

        poll.state = BasePoll.STATE_FINISHED
        poll.save()
        inform_changed_data(poll.get_votes())
        inform_changed_data(poll.get_options())
        return Response()
Ejemplo n.º 3
0
 def withdraw_self(self, request, assignment):
     # Withdraw candidature.
     if assignment.phase == assignment.PHASE_FINISHED:
         raise ValidationError({
             'detail':
             _('You can not withdraw your candidature to this election because it is finished.'
               )
         })
     if assignment.phase == assignment.PHASE_VOTING and not has_perm(
             request.user, 'assignments.can_manage'):
         # To withdraw self during voting you have to be a manager.
         self.permission_denied(request)
     if not assignment.is_candidate(request.user):
         raise ValidationError(
             {'detail': _('You are not a candidate of this election.')})
     assignment.delete_related_user(request.user)
     return _('You have withdrawn your candidature successfully.')
Ejemplo n.º 4
0
 def delete_other(self, request, user, assignment):
     # To delete candidature status you have to be a manager.
     if not has_perm(request.user, 'assignments.can_manage'):
         self.permission_denied(request)
     if assignment.phase == assignment.PHASE_FINISHED:
         detail = _(
             "You can not delete someone's candidature to this election because it is finished."
         )
         raise ValidationError({'detail': detail})
     if not assignment.is_candidate(user) and not assignment.is_elected(
             user):
         raise ValidationError({
             'detail':
             _('User %s has no status in this election.') % user
         })
     assignment.delete_related_user(user)
     return _('Candidate %s was withdrawn successfully.') % user
Ejemplo n.º 5
0
 def nominate_other(self, request, user, assignment):
     if assignment.is_elected(user):
         raise ValidationError(
             {'detail': _('User %s is already elected.') % user})
     if assignment.phase == assignment.PHASE_FINISHED:
         detail = _(
             'You can not nominate someone to this election because it is finished.'
         )
         raise ValidationError({'detail': detail})
     if assignment.phase == assignment.PHASE_VOTING and not has_perm(
             request.user, 'assignments.can_manage'):
         # To nominate another user during voting you have to be a manager.
         self.permission_denied(request)
     if assignment.is_candidate(user):
         raise ValidationError(
             {'detail': _('User %s is already nominated.') % user})
     assignment.set_candidate(user)
     return _('User %s was nominated successfully.') % user
Ejemplo n.º 6
0
def validate_workflow_field(value):
    """
    Validator to ensure that the workflow with the given id exists.
    """
    if not Workflow.objects.filter(pk=value).exists():
        raise ValidationError(
            {'detail': _('Workflow %(pk)d does not exist.') % {
                'pk': value
            }})
Ejemplo n.º 7
0
    def start(self, request, pk):
        poll = self.get_object()
        if poll.state != BasePoll.STATE_CREATED:
            raise ValidationError({"detail": "Wrong poll state"})
        poll.state = BasePoll.STATE_STARTED

        poll.save()
        inform_changed_data(poll.get_votes())
        return Response()
Ejemplo n.º 8
0
def posts_validator(data):
    """
    Validator for open posts. It checks that the values for the open posts are greater than 0.
    """
    if data["open_posts"] and data[
            "open_posts"] is not None and data["open_posts"] < 1:
        raise ValidationError(
            {"detail": "Value for 'open_posts' must be greater than 0"})
    return data
Ejemplo n.º 9
0
    def generate(self, request):
        """
        Generate n tokens. Provide N (1<=N<=4096) as the only argument: {N: <n>}
        """
        if not isinstance(request.data, dict):
            raise ValidationError({'detail': 'The data has to be a dict.'})
        n = request.data.get('N')
        if not isinstance(n, int):
            raise ValidationError({'detail': 'N has to be an int.'})
        if n < 1 or n > 4096:
            raise ValidationError(
                {'detail': 'N has to be between 1 and 4096.'})

        # no I,O,i,l,o,0
        choices = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrsuvwxyz123456789'
        tokens = [(''.join(random.choice(choices) for _ in range(12)))
                  for _ in range(n)]
        return Response(tokens)
Ejemplo n.º 10
0
    def stop(self, request, pk):
        poll = self.get_locked_object()
        # Analog polls cannot be stopped; they are stopped when
        # the results are entered.
        if poll.type == BasePoll.TYPE_ANALOG:
            raise ValidationError({
                "detail":
                "Analog polls can not be stopped. Please enter votes."
            })

        if poll.state != BasePoll.STATE_STARTED:
            raise ValidationError({"detail": "Wrong poll state"})

        poll.stop()
        inform_changed_data(poll.get_votes())
        inform_changed_data(poll.get_options())
        self.extend_history_information(["Voting stopped"])
        return Response()
Ejemplo n.º 11
0
    def set_resolution(self, request, pk):
        """
        REST API operation to set the resolution.

        It is actually unused, because the resolution is currently set in the config.
        But with the multiprojector feature this will become importent to set the
        resolution per projector individually.

        It expects a POST request to
        /rest/core/projector/<pk>/set_resolution/ with a dictionary with the width
        and height and the values.

        Example:

        {
            "width": "1024",
            "height": "768"
        }
        """
        if not isinstance(request.data, dict):
            raise ValidationError({'detail': 'Data must be a dictionary.'})
        if request.data.get('width') is None or request.data.get(
                'height') is None:
            raise ValidationError(
                {'detail': 'A width and a height have to be given.'})
        if not isinstance(request.data['width'], int) or not isinstance(
                request.data['height'], int):
            raise ValidationError({'detail': 'Data has to be integers.'})
        if (request.data['width'] < 800 or request.data['width'] > 3840
                or request.data['height'] < 600
                or request.data['height'] > 2160):
            raise ValidationError({
                'detail':
                'The Resolution have to be between 800x600 and 3840x2160.'
            })

        projector_instance = self.get_object()
        projector_instance.width = request.data['width']
        projector_instance.height = request.data['height']
        projector_instance.save()

        message = 'Changing resolution to {width}x{height} was successful.'.format(
            width=request.data['width'], height=request.data['height'])
        return Response({'detail': message})
Ejemplo n.º 12
0
    def set_state(self, request, pk=None):
        """
        Special view endpoint to set and reset a state of a motion.

        Send PUT {'state': <state_id>} to set and just PUT {} to reset the
        state. Only managers can use this view.
        """
        # Retrieve motion and state.
        motion = self.get_object()
        state = request.data.get('state')

        # Set or reset state.
        if state is not None:
            # Check data and set state.
            try:
                state_id = int(state)
            except ValueError:
                raise ValidationError(
                    {'detail': _('Invalid data. State must be an integer.')})
            if state_id not in [
                    item.id for item in motion.state.next_states.all()
            ]:
                raise ValidationError({
                    'detail':
                    _('You can not set the state to %(state_id)d.') % {
                        'state_id': state_id
                    }
                })
            motion.set_state(state_id)
        else:
            # Reset state.
            motion.reset_state()

        # Save motion.
        motion.save(update_fields=['state', 'identifier'])
        message = _(
            'The state of the motion was set to %s.') % motion.state.name

        # Write the log message and initiate response.
        motion.write_log(message_list=[
            ugettext_noop('State set to'), ' ', motion.state.name
        ],
                         person=request.user)
        return Response({'detail': message})
Ejemplo n.º 13
0
    def assert_can_vote(self, poll, request, vote_user):
        """
        Raises a permission denied, if the user is not allowed to vote (or has already voted).
        Adds the user to the voted array, so this needs to be reverted if a later error happens!
        Analog:                     has to have manage permissions
        Named & Pseudoanonymous:    has to be in a poll group and present
        """
        # if the request user is not the vote user, the delegation must be right
        if request.user != vote_user and request.user != vote_user.vote_delegated_to:
            raise ValidationError(
                {
                    "detail": f"You cannot vote for {vote_user.id} since the vote right was not delegated to you."
                }
            )

        # If the request user is the vote user, this user must not have any delegation.
        # It is not allowed to vote for oneself, if the vote is delegated
        if request.user == vote_user and request.user.vote_delegated_to is not None:
            raise ValidationError(
                {"detail": "You cannot vote since your vote right is delegated."}
            )

        if poll.type == BasePoll.TYPE_ANALOG:
            if not self.has_manage_permissions():
                self.permission_denied(request)
        else:
            if poll.state != BasePoll.STATE_STARTED:
                raise ValidationError(
                    {"detail": "You can only vote on a started poll."}
                )

            if not request.user.is_present or not in_some_groups(
                vote_user.id,
                list(poll.groups.values_list("pk", flat=True)),
                exact=True,
            ):
                self.permission_denied(request)

            try:
                self.add_user_to_voted_array(vote_user, poll)
                inform_changed_data(poll)
            except IntegrityError:
                raise ValidationError({"detail": "You have already voted."})
Ejemplo n.º 14
0
    def start(self, request, pk):
        poll = self.get_locked_object()
        if poll.state != BasePoll.STATE_CREATED:
            raise ValidationError({"detail": "Wrong poll state"})
        poll.state = BasePoll.STATE_STARTED

        poll.save()
        inform_changed_data(poll.get_votes())
        self.extend_history_information(["Voting started"])
        return Response()
Ejemplo n.º 15
0
 def delete_other(self, request, user, assignment):
     # To delete candidature status you have to be a manager.
     if not has_perm(request.user, "assignments.can_manage"):
         self.permission_denied(request)
     if assignment.phase == assignment.PHASE_FINISHED:
         raise ValidationError({
             "detail":
             "You can not delete someone's candidature to this election because it is finished."
         })
     if not assignment.is_candidate(user):
         raise ValidationError({
             "detail": "User {0} has no status in this election.",
             "args": [str(user)],
         })
     assignment.remove_candidate(user)
     return Response({
         "detail": "Candidate {0} was withdrawn successfully.",
         "args": [str(user)]
     })
Ejemplo n.º 16
0
    def sort_related_users(self, request, pk=None):
        """
        Special view endpoint to sort the assignment related users.

        Expects a list of IDs of the related users (pk of AssignmentRelatedUser model).
        """
        assignment = self.get_object()

        # Check data
        related_user_ids = request.data.get("related_users")
        if not isinstance(related_user_ids, list):
            raise ValidationError({"detail": "users has to be a list of IDs."})

        # Get all related users from AssignmentRelatedUser.
        related_users = {}
        for related_user in AssignmentRelatedUser.objects.filter(
            assignment__id=assignment.id
        ):
            related_users[related_user.pk] = related_user

        # Check all given candidates from the request
        valid_related_users = []
        for related_user_id in related_user_ids:
            if (
                not isinstance(related_user_id, int)
                or related_users.get(related_user_id) is None
            ):
                raise ValidationError({"detail": "Invalid data."})
            valid_related_users.append(related_users[related_user_id])

        # Sort the related users
        weight = 1
        with transaction.atomic():
            for valid_related_user in valid_related_users:
                valid_related_user.weight = weight
                valid_related_user.save(skip_autoupdate=True)
                weight += 1

        # send autoupdate
        inform_changed_data(assignment)

        # Initiate response.
        return Response({"detail": "Assignment related users successfully sorted."})
Ejemplo n.º 17
0
    def bulk_delete(self, request):
        """
        Deletes mediafiles *from one directory*. Expected data:
        { ids: [<id>, <id>, ...] }
        It is checked, that every id belongs to the same directory.
        """
        # Validate data:
        if not isinstance(request.data, dict):
            raise ValidationError({"detail": "The data must be a dict"})
        ids = request.data.get("ids")
        if not isinstance(ids, list):
            raise ValidationError({"detail": "The ids must be a list"})
        for id in ids:
            if not isinstance(id, int):
                raise ValidationError({"detail": "All ids must be an int"})

        # Get mediafiles
        mediafiles = []
        for id in ids:
            try:
                mediafiles.append(Mediafile.objects.get(pk=id))
            except Mediafile.DoesNotExist:
                raise ValidationError({
                    "detail": "The mediafile with id {0} does not exist",
                    "args": [id]
                })
        if not mediafiles:
            return Response()

        # Validate, that they are in the same directory:
        directory_id = mediafiles[0].parent_id
        for mediafile in mediafiles:
            if mediafile.parent_id != directory_id:
                raise ValidationError({
                    "detail":
                    "All mediafiles must be in the same directory."
                })

        with watch_and_update_configs():
            for mediafile in mediafiles:
                mediafile.delete()

        return Response()
Ejemplo n.º 18
0
 def validate(self, data):
     is_valid_int = False
     try:
         int_vote = int(data['vote'])
         if int_vote > 0:
             is_valid_int = True
     except:
         pass
     if data['vote'] not in ('Y', 'N', 'A') and not is_valid_int:
         raise ValidationError({'detail': 'The vote intention for assignments can only be Y, N, A or an integer greater then 0.'})
     return data
Ejemplo n.º 19
0
 def create_poll(self, request, pk=None):
     """
     View to create a poll. It is a POST request without any data.
     """
     motion = self.get_object()
     try:
         with transaction.atomic():
             motion.create_poll()
     except WorkflowError as e:
         raise ValidationError({'detail': e})
     return Response({'detail': _('Vote created successfully.')})
Ejemplo n.º 20
0
    def numbering(self, request):
        """
        Auto numbering of the agenda according to the config. Manually added
        item numbers will be overwritten.
        """
        if not config['agenda_enable_numbering']:
            raise ValidationError(
                {'detail': _('Numbering of agenda items is deactivated.')})

        Item.objects.number_all(numeral_system=config['agenda_numeral_system'])
        return Response({'detail': _('The agenda has been numbered.')})
Ejemplo n.º 21
0
def posts_validator(data):
    """
    Validator for open posts. It checks that the values for the open posts are greater than 0.
    """
    if (data['open_posts'] and data['open_posts'] is not None
            and data['open_posts'] < 1):
        raise ValidationError({
            'detail':
            _('Value for {} must be greater than 0').format('open_posts')
        })
    return data
Ejemplo n.º 22
0
    def start_speaker_list(self, request, **kwargs):
        """
        Starts a voting for the speakers list. The item id has to be given as the only argument:
        {item_id: <item_id>}
        """
        # Requires the votecollector.
        if not config['voting_enable_votecollector']:
            raise ValidationError(
                {'detail': 'The VoteCollector is not enabled'})

        vc = self.get_object()
        item, item_id = self.get_request_object(request,
                                                Item,
                                                attr_name='item_id')

        # Stop any active voting no matter what mode.
        self.force_stop_active_votecollector()

        url = rpc.get_callback_url(request) + '/speaker/' + str(item_id) + '/'

        try:
            vc.votes_count, vc.device_status = rpc.start_voting(
                'SpeakerList', url)
        except rpc.VoteCollectorError as e:
            raise ValidationError({'detail': e.value})

        vc.voting_mode = 'Item'
        vc.voting_target = item_id
        vc.votes_received = 0
        vc.is_voting = True
        vc.principle = None
        vc.save()

        projector = Projector.objects.get(id=1)
        projector.config[self.prompt_key] = {
            'name': 'voting/icon',
            'stable': True
        }
        projector.save(information={'voting_prompt': True})

        return Response()
Ejemplo n.º 23
0
 def nominate_other(self, request, user, assignment):
     if assignment.is_elected(user):
         raise ValidationError(
             {"detail": f"User {user} is already elected."})
     if assignment.phase == assignment.PHASE_FINISHED:
         detail = (
             "You can not nominate someone to this election because it is finished."
         )
         raise ValidationError({"detail": detail})
     if assignment.phase == assignment.PHASE_VOTING and not has_perm(
             request.user, "assignments.can_manage"):
         # To nominate another user during voting you have to be a manager.
         self.permission_denied(request)
     if assignment.is_candidate(user):
         raise ValidationError(
             {"detail": f"User {user} is already nominated."})
     assignment.set_candidate(user)
     # Send new candidate via autoupdate because users without permission
     # to see users may not have it but can get it now.
     inform_changed_data(user)
     return f"User {user} was nominated successfully."
Ejemplo n.º 24
0
    def publish(self, request, pk):
        poll = self.get_object()
        if poll.state != BasePoll.STATE_FINISHED:
            raise ValidationError({"detail": "Wrong poll state"})

        poll.state = BasePoll.STATE_PUBLISHED
        poll.save()
        inform_changed_data(vote.user for vote in poll.get_votes().all()
                            if vote.user)
        inform_changed_data(poll.get_votes())
        inform_changed_data(poll.get_options())
        return Response()
Ejemplo n.º 25
0
 def create_poll(self, request, pk=None):
     """
     View to create a poll. It is a POST request without any data.
     """
     assignment = self.get_object()
     if not assignment.candidates.exists():
         raise ValidationError({
             'detail':
             _('Can not create ballot because there are no candidates.')
         })
     with transaction.atomic():
         assignment.create_poll()
     return Response({'detail': _('Ballot created successfully.')})
Ejemplo n.º 26
0
    def candidature_other(self, request, pk=None):
        """
        View to nominate other users (POST) or delete their candidature
        status (DELETE). The client has to send {'user': <id>}.
        """
        user_id = request.data.get("user")
        if not isinstance(user_id, int):
            raise ValidationError({"detail": "user_id must be an int."})

        try:
            user = get_user_model().objects.get(pk=user_id)
        except get_user_model().DoesNotExist:
            raise ValidationError(
                {"detail": "Invalid data. User {0} does not exist.", "args": [user_id]}
            )

        assignment = self.get_object()
        if request.method == "POST":
            return self.nominate_other(request, user, assignment)
        else:
            # request.method == 'DELETE'
            return self.withdraw_other(request, user, assignment)
Ejemplo n.º 27
0
    def update(self, request, *args, **kwargs):
        """
        Updates a config variable. Only managers can do this.

        Example: {"value": 42}
        """
        key = kwargs['pk']
        value = request.data.get('value')
        if value is None:
            raise ValidationError(
                {'detail': 'Invalid input. Config value is missing.'})

        # Validate and change value.
        try:
            config[key] = value
        except ConfigNotFound:
            raise Http404
        except ConfigError as e:
            raise ValidationError({'detail': str(e)})

        # Return response.
        return Response({'key': key, 'value': value})
Ejemplo n.º 28
0
    def perform_create(self, serializer):
        assignment = serializer.validated_data["assignment"]
        if not assignment.candidates.exists():
            raise ValidationError(
                {"detail": "Cannot create poll because there are no candidates."}
            )

        super().perform_create(serializer)
        poll = AssignmentPoll.objects.get(pk=serializer.data["id"])
        poll.db_amount_global_yes = Decimal(0)
        poll.db_amount_global_no = Decimal(0)
        poll.db_amount_global_abstain = Decimal(0)
        poll.save()
Ejemplo n.º 29
0
    def speak(self, request, pk=None):
        """
        Special view endpoint to begin and end speech of speakers. Send PUT
        {'speaker': <speaker_id>} to begin speech. Omit data to begin speech of
        the next speaker. Send DELETE to end speech of current speaker.
        """
        # Retrieve item.
        item = self.get_object()

        if request.method == 'PUT':
            # Retrieve speaker_id
            speaker_id = request.data.get('speaker')
            if speaker_id is None:
                speaker = item.get_next_speaker()
                if speaker is None:
                    raise ValidationError({'detail': _('The list of speakers is empty.')})
            else:
                try:
                    speaker = Speaker.objects.get(pk=int(speaker_id))
                except (ValueError, Speaker.DoesNotExist):
                    raise ValidationError({'detail': _('Speaker does not exist.')})
            speaker.begin_speech()
            message = _('User is now speaking.')

        else:
            # request.method == 'DELETE'
            try:
                # We assume that there aren't multiple entries because this
                # is forbidden by the Model's begin_speech method. We assume that
                # there is only one speaker instance or none.
                current_speaker = Speaker.objects.filter(item=item, end_time=None).exclude(begin_time=None).get()
            except Speaker.DoesNotExist:
                raise ValidationError(
                    {'detail': _('There is no one speaking at the moment according to %(item)s.') % {'item': item}})
            current_speaker.end_speech()
            message = _('The speech is finished now.')

        # Initiate response.
        return Response({'detail': message})
Ejemplo n.º 30
0
    def sort_speakers(self, request, pk=None):
        """
        Special view endpoint to sort the list of speakers.

        Expects a list of IDs of the speakers.
        """
        # Retrieve item.
        item = self.get_object()

        # Check data
        speaker_ids = request.data.get('speakers')
        if not isinstance(speaker_ids, list):
            raise ValidationError({'detail': _('Invalid data.')})

        # Get all speakers
        speakers = {}
        for speaker in item.speakers.filter(begin_time=None):
            speakers[speaker.pk] = speaker

        # Check and sort speakers
        valid_speakers = []
        for speaker_id in speaker_ids:
            if not isinstance(speaker_id,
                              int) or speakers.get(speaker_id) is None:
                raise ValidationError({'detail': _('Invalid data.')})
            valid_speakers.append(speakers[speaker_id])
        weight = 0
        with transaction.atomic():
            for speaker in valid_speakers:
                speaker.weight = weight
                speaker.save(skip_autoupdate=True)
                weight += 1

        # send autoupdate
        inform_changed_data(item)

        # Initiate response.
        return Response({'detail': _('List of speakers successfully sorted.')})