Exemple #1
0
    def assign(self, request):
        """
        Assign multiple agenda items to a new parent item.

        Send POST {... see schema ...} to assign the new parent.

        This aslo checks the parent field to prevent hierarchical loops.
        """
        schema = {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "title": "Agenda items assign new parent schema",
            "description":
            "An object containing an array of agenda item ids and the new parent id the items should be assigned to.",
            "type": "object",
            "propterties": {
                "items": {
                    "description":
                    "An array of agenda item ids where the items should be assigned to the new parent id.",
                    "type": "array",
                    "items": {
                        "type": "integer"
                    },
                    "minItems": 1,
                    "uniqueItems": True,
                },
                "parent_id": {
                    "description":
                    "The agenda item id of the new parent item.",
                    "type": "integer",
                },
            },
            "required": ["items", "parent_id"],
        }

        # Validate request data.
        try:
            jsonschema.validate(request.data, schema)
        except jsonschema.ValidationError as err:
            raise ValidationError({"detail": str(err)})

        # Check parent item
        try:
            parent = Item.objects.get(pk=request.data["parent_id"])
        except Item.DoesNotExist:
            raise ValidationError({
                "detail":
                f"Parent item {request.data['parent_id']} does not exist"
            })

        # Collect ancestors
        ancestors = [parent.pk]
        grandparent = parent.parent
        while grandparent is not None:
            ancestors.append(grandparent.pk)
            grandparent = grandparent.parent

        # First validate all items before changeing them.
        items = []
        for item_id in request.data["items"]:
            # Prevent hierarchical loops.
            if item_id in ancestors:
                raise ValidationError({
                    "detail":
                    f"Assigning item {item_id} to one of its children is not possible."
                })

            # Check every item
            try:
                items.append(Item.objects.get(pk=item_id))
            except Item.DoesNotExist:
                raise ValidationError(
                    {"detail": f"Item {item_id} does not exist"})

        # OK, assign new parents.
        for item in items:
            # Assign new parent.
            item.parent = parent
            item.save(skip_autoupdate=True)

        # Now inform all clients.
        inform_changed_data(items)

        # Send response.
        return Response(
            {"detail": f"{len(items)} items successfully assigned."})
Exemple #2
0
 def reset(self, request, pk):
     poll = self.get_object()
     poll.reset()
     self.extend_history_information(["Voting reset"])
     return Response()
Exemple #3
0
 def refresh(self, request, pk):
     poll = self.get_object()
     inform_changed_data(poll)
     inform_changed_data(poll.get_options())
     inform_changed_data(poll.get_votes())
     return Response()
Exemple #4
0
    def create(self, request, *args, **kwargs):
        """
        Customized view endpoint to upload a new file.
        """
        # The form data may send the groups_id
        if isinstance(request.data, QueryDict):
            request.data._mutable = True

        self.convert_access_groups(request)

        is_directory = bool(request.data.get("is_directory", False))
        mediafile = request.data.get("mediafile")

        # Check, that it is either a file or a directory
        if is_directory and mediafile:
            raise ValidationError(
                {"detail": "Either create a path or a file, but not both"}
            )
        if not mediafile and not is_directory:
            raise ValidationError({"detail": "You forgot to provide a file."})

        if mediafile:
            if mediafile.size > max_upload_size:
                max_size_for_humans = bytes_to_human(max_upload_size)
                raise ValidationError(
                    {"detail": f"The maximum upload file size is {max_size_for_humans}"}
                )

            # set original filename
            request.data["original_filename"] = mediafile.name

            # Remove mediafile from request.data, we will put it into the storage ourself.
            request.data.pop("mediafile", None)

        # Create mediafile
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        db_mediafile = serializer.save()

        # Set filesize, mimetype and check for pdfs.
        if mediafile:
            db_mediafile.filesize = bytes_to_human(mediafile.size)
            db_mediafile.mimetype = mediafile.content_type
            if db_mediafile.mimetype == "application/pdf":
                db_mediafile.pdf_information = get_pdf_information(mediafile)
            else:
                db_mediafile.pdf_information = {}
            db_mediafile.save()

            # Custom modifications for the database storage: Set original filename here and
            # insert the file into the foreing storage
            if use_mediafile_database:
                with connections["mediafiles"].cursor() as cursor:
                    cursor.execute(
                        "INSERT INTO mediafile_data (id, data, mimetype) VALUES (%s, %s, %s)",
                        [
                            db_mediafile.id,
                            mediafile.open().read(),
                            mediafile.content_type,
                        ],
                    )
            else:
                db_mediafile.mediafile = mediafile
                db_mediafile.save()

        return Response(data={"id": db_mediafile.id}, status=status.HTTP_201_CREATED)
    def start_voting(self, request, model):
        vc = self.get_object()
        poll, poll_id = self.get_request_object(request, model)

        # get voting principle and type from motion or assignment
        principle = None
        voting_type = None
        # Get candidate name (if is an election with one candidate only)
        candidate_str = ''
        # projector message and images
        projector_yes = '<button type="button" class="btn btn-default btn-voting-sm btn-yes"> \
            <i class="fa fa-thumbs-o-up fa-2x"></i></button>'

        projector_no = '<button type="button" class="btn btn-default btn-voting-sm btn-no"> \
            <i class="fa fa-thumbs-o-down fa-2x"></i></button>'

        projector_abstain = '<button type="button" class="btn btn-default btn-voting-sm btn-abstain"> \
            <i class="fa fa-circle-o fa-2x"></i></button>'

        if type(poll) == MotionPoll:
            projector_message = _(config['voting_start_prompt_motions'])
            principle = VotingPrinciple.get(motion=poll.motion)

            try:
                voting_type = MotionPollType.objects.get(poll=poll).type
            except MotionPollType.DoesNotExist:
                voting_type = config['voting_default_voting_type']

            if voting_type.startswith('votecollector'):
                if 'Interact' in vc.device_status:
                    projector_abstain = '2 = '
                elif 'Reply' in vc.device_status:
                    projector_yes = '1 = '
                    projector_no = '2 = '
                    projector_abstain = '3 = '
                projector_message += '<br>' + \
                '<span class="nobr">' + projector_yes + _('Yes') + '</span>&nbsp;' + \
                '<span class="nobr spacer-left">' + projector_no + _('No') + '</span>&nbsp;' + \
                '<span class="nobr spacer-left">' + projector_abstain + _('Abstain') + '</span>'

            votecollector_mode = 'YesNoAbstain'
            votecollector_options = None
            votecollector_resource = '/vote/'

            ballot = MotionBallot(poll, principle)
        elif type(poll) == AssignmentPoll:
            projector_message = _(config['voting_start_prompt_assignments'])
            principle = VotingPrinciple.get(assignment=poll.assignment)

            try:
                voting_type = AssignmentPollType.objects.get(poll=poll).type
            except AssignmentPollType.DoesNotExist:
                voting_type = config['voting_default_voting_type']

            options = AssignmentOption.objects.filter(
                poll=poll).order_by('weight')
            # check, if the pollmethod is supported by the votecollector
            # If so, calculate the projector message for the voting prompt
            if voting_type.startswith('votecollector'):
                if poll.pollmethod == 'yn' or (poll.pollmethod == 'yna'
                                               and options.count() is not 1):
                    raise ValidationError({
                        'detail':
                        'The votecollector does not support the pollmethod {} (with {} candidates).'
                        .format(poll.pollmethod, options.count())
                    })

                if 'Interact' in vc.device_status:
                    projector_abstain = '2 = '
                elif 'Reply' in vc.device_status:
                    projector_yes = '1 = '
                    projector_no = '2 = '
                    projector_abstain = '3 = '

                # calculate the candidate string
                if poll.pollmethod == 'yna':
                    candidate = str(options.all()[0].candidate)
                    projector_message += '<br>' + \
                        '<span class="nobr">' + projector_yes + _('Yes') + '</span>&nbsp;' + \
                        '<span class="nobr">' + projector_no + _('No') + '</span>&nbsp;' + \
                        '<span class="nobr">' + projector_abstain + _('Abstain') + '</span>' + \
                        '<div class="spacer candidate">' + candidate + '</div>'

                    votecollector_mode = 'YesNoAbstain'
                    votecollector_options = None
                    votecollector_resource = '/vote/'
                else:  # votes
                    projector_message += '<div><ul class="columns" data-columns="3">'
                    for index, option in enumerate(options.all()):
                        projector_message += \
                                '<li><span class="key">' + str(index + 1) + '</span>' + \
                                '<span class="candidate">' + str(option.candidate) + '</span></li>'
                    projector_message += '<li><span class="key">0</span><span class="candidate">' + \
                        _('Abstain') + '</span></li></ul></div>'

                    if options.count() < 10:
                        votecollector_mode = 'SingleDigit'
                        votecollector_options = '10'  # unlock all keys 0 to 9
                    else:
                        votecollector_mode = 'MultiDigit'
                        votecollector_options = '2'  # limit votes to 2 digits, only applies to simulator
                    votecollector_resource = '/candidate/'

            ballot = AssignmentBallot(poll)
        else:
            raise ValidationError(
                {'detail': 'Not supported type {}.'.format(type(poll))})

        # Delete all old votes and create absentee ballots
        ballot.delete_ballots()
        absentee_ballots_created = 0
        if config['voting_enable_proxies']:
            absentee_ballots_created = ballot.create_absentee_ballots()

        if voting_type.startswith('votecollector'):
            if not config['voting_enable_votecollector']:
                raise ValidationError(
                    {'detail': 'The VoteCollector is not enabled'})

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

            url = rpc.get_callback_url(request) + votecollector_resource
            url += '%s/' % poll_id

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

            # Limit voters count to length of admitted delegates list.
            admitted_count, admitted_delegates = get_admitted_delegates(
                principle, keypad=True)
            if not voting_type == 'votecollector_anonymous':
                vc.votes_count = admitted_count

        elif voting_type == 'named_electronic':
            # Limit voters count to length of admitted delegates list.
            vc.votes_count, admitted_delegates = get_admitted_delegates(
                principle)

        else:  # 'token_based_electronic'
            admitted_delegates = None
            vc.votes_count = 0  # We do not know, how many votes will come..

        vc.voting_mode = model.__name__
        vc.voting_target = poll_id
        vc.votes_received = absentee_ballots_created
        vc.is_voting = True
        vc.principle = principle
        vc.save()

        # Update AuthorizedVoter object
        if type(poll) == MotionPoll:
            AuthorizedVoters.set_voting(admitted_delegates,
                                        voting_type,
                                        motion_poll=poll)
        else:
            AuthorizedVoters.set_voting(admitted_delegates,
                                        voting_type,
                                        assignment_poll=poll)

        # Add projector message
        # search projector with an projected "related item". This item might be the motion/assignment
        # itself or the voting/(motion/assignment)-poll slide. If none was found, use the default projector

        if type(poll) == MotionPoll:
            objectElementName = 'motions/motion'
            objectElementId = poll.motion.id
            pollElementName = 'voting/motion-poll'
        else:
            objectElementName = 'assignments/assignment'
            objectElementId = poll.assignment.id
            pollElementName = 'voting/assignment-poll'

        projector = None
        found_projector = False
        for p in Projector.objects.all():
            if found_projector:
                break
            for uuid, element in p.elements.items():
                if found_projector:
                    break
                if element['name'] == objectElementName and element[
                        'id'] == objectElementId:
                    projector = p
                    found_projector = True
                if element['name'] == pollElementName and element[
                        'id'] == poll_id:
                    projector = p
                    found_projector = True
        if not found_projector:
            projector = Projector.objects.get(id=1)

        projector.config[self.prompt_key] = {
            'name': 'voting/prompt',
            'message': projector_message,
            'stable': True
        }

        # Auto start countdown and add it to projector.
        if config['voting_auto_countdown']:
            # Use countdown 2 since 1 is reserved for speakers list.
            countdown, created = Countdown.objects.get_or_create(
                pk=2,
                description=_('Poll is open'),
                defaults={
                    'default_time': config['projector_default_countdown'],
                    'countdown_time': config['projector_default_countdown']
                })
            if not created:
                countdown.control(action='reset')
            countdown.control(action='start')
            projector.config[self.countdown_key] = {
                'name': 'core/countdown',
                'id': 2,
                'stable': True
            }
        projector.save(information={'voting_prompt': True})

        return Response()
Exemple #6
0
    def manage_speaker(self, request, pk=None):
        """
        Special view endpoint to add users to the list of speakers or remove
        them. Send POST {'user': <user_id>} to add a new speaker. Omit
        data to add yourself. Send DELETE {'speaker': <speaker_id>} or
        DELETE {'speaker': [<speaker_id>, <speaker_id>, ...]} to remove one or
        more speakers from the list of speakers. Omit data to remove yourself.
        Send PATCH {'user': <user_id>, 'marked': <bool>} to mark the speaker.

        Checks also whether the requesting user can do this. He needs at
        least the permissions 'agenda.can_see' (see
        self.check_view_permissions()). In case of adding himself the
        permission 'agenda.can_be_speaker' is required. In case of adding
        someone else the permission 'agenda.can_manage' is required. In
        case of removing someone else 'agenda.can_manage' is required. In
        case of removing himself no other permission is required.
        """
        # Retrieve item.
        item = self.get_object()

        if request.method == 'POST':
            # Retrieve user_id
            user_id = request.data.get('user')

            # Check permissions and other conditions. Get user instance.
            if user_id is None:
                # Add oneself
                if not has_perm(self.request.user, 'agenda.can_be_speaker'):
                    self.permission_denied(request)
                if item.speaker_list_closed:
                    raise ValidationError(
                        {'detail': _('The list of speakers is closed.')})
                user = self.request.user
            else:
                # Add someone else.
                if not has_perm(self.request.user,
                                'agenda.can_manage_list_of_speakers'):
                    self.permission_denied(request)
                try:
                    user = get_user_model().objects.get(pk=int(user_id))
                except (ValueError, get_user_model().DoesNotExist):
                    raise ValidationError(
                        {'detail': _('User does not exist.')})

            # Try to add the user. This ensurse that a user is not twice in the
            # list of coming speakers.
            try:
                Speaker.objects.add(user, item)
            except OpenSlidesError as e:
                raise ValidationError({'detail': str(e)})
            message = _(
                'User %s was successfully added to the list of speakers.'
            ) % user

            # Send new speaker via autoupdate because users without permission
            # to see users may not have it but can get it now.
            inform_changed_data([user])

        # Toggle 'marked' for the speaker
        elif request.method == 'PATCH':
            # Check permissions
            if not has_perm(self.request.user,
                            'agenda.can_manage_list_of_speakers'):
                self.permission_denied(request)

            # Retrieve user_id
            user_id = request.data.get('user')
            try:
                user = get_user_model().objects.get(pk=int(user_id))
            except (ValueError, get_user_model().DoesNotExist):
                raise ValidationError({'detail': _('User does not exist.')})

            marked = request.data.get('marked')
            if not isinstance(marked, bool):
                raise ValidationError(
                    {'detail': _('Marked has to be a bool.')})

            queryset = Speaker.objects.filter(item=item, user=user)
            try:
                # We assume that there aren't multiple entries because this
                # is forbidden by the Manager's add method. We assume that
                # there is only one speaker instance or none.
                speaker = queryset.get()
            except Speaker.DoesNotExist:
                raise ValidationError(
                    {'detail': _('The user is not in the list of speakers.')})
            else:
                speaker.marked = marked
                speaker.save()
                if speaker.marked:
                    message = _('You are successfully marked the speaker.')
                else:
                    message = _('You are successfully unmarked the speaker.')

        else:
            # request.method == 'DELETE'
            speaker_ids = request.data.get('speaker')

            # Check permissions and other conditions. Get speaker instance.
            if speaker_ids is None:
                # Remove oneself
                queryset = Speaker.objects.filter(
                    item=item, user=self.request.user).exclude(weight=None)
                try:
                    # We assume that there aren't multiple entries because this
                    # is forbidden by the Manager's add method. We assume that
                    # there is only one speaker instance or none.
                    speaker = queryset.get()
                except Speaker.DoesNotExist:
                    raise ValidationError(
                        {'detail': _('You are not on the list of speakers.')})
                else:
                    speaker.delete()
                    message = _(
                        'You are successfully removed from the list of speakers.'
                    )
            else:
                # Remove someone else.
                if not has_perm(self.request.user,
                                'agenda.can_manage_list_of_speakers'):
                    self.permission_denied(request)
                if type(speaker_ids) is int:
                    speaker_ids = [speaker_ids]
                deleted_speaker_count = 0
                for speaker_id in speaker_ids:
                    try:
                        speaker = Speaker.objects.get(pk=int(speaker_id))
                    except (ValueError, Speaker.DoesNotExist):
                        pass
                    else:
                        speaker.delete(skip_autoupdate=True)
                        deleted_speaker_name = speaker
                        deleted_speaker_count += 1
                # send autoupdate if speakers are deleted
                if deleted_speaker_count > 0:
                    inform_changed_data(item)

                if deleted_speaker_count > 1:
                    message = str(deleted_speaker_count) + ' ' + _(
                        'speakers have been removed from the list of speakers.'
                    )
                elif deleted_speaker_count == 1:
                    message = _(
                        'User %s has been removed from the list of speakers.'
                    ) % deleted_speaker_name
                else:
                    message = _(
                        'No speakers have been removed from the list of speakers.'
                    )
        # Initiate response.
        return Response({'detail': message})
Exemple #7
0
    def move(self, request):
        """
        {
            ids: [<id>, <id>, ...],
            directory_id: <id>
        }
        Move <ids> to the given directory_id. This will raise an error, if
        the move would be recursive.
        """

        # 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"})
        directory_id = request.data.get("directory_id")
        if directory_id is not None and not isinstance(directory_id, int):
            raise ValidationError({"detail": "The directory_id must be an int"})
        if directory_id is None:
            directory = None
        else:
            try:
                directory = Mediafile.objects.get(pk=directory_id, is_directory=True)
            except Mediafile.DoesNotExist:
                raise ValidationError({"detail": "The directory does not exist"})

        ids_set = set(ids)  # keep them in a set for fast lookup
        ids = list(ids_set)  # make ids unique

        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]}
                )

        # Search for valid parents (None is not included, but also safe!)
        if directory is not None:
            valid_parent_ids = set()

            queue = list(Mediafile.objects.filter(parent=None, is_directory=True))
            for mediafile in queue:
                if mediafile.pk in ids_set:
                    continue  # not valid, because this is in the input data
                valid_parent_ids.add(mediafile.pk)
                queue.extend(
                    list(Mediafile.objects.filter(parent=mediafile, is_directory=True))
                )

            if directory_id not in valid_parent_ids:
                raise ValidationError({"detail": "The directory is not valid"})

        # Ok, update all mediafiles
        with watch_and_update_configs():
            for mediafile in mediafiles:
                mediafile.parent = directory
                mediafile.save(skip_autoupdate=True)
        if directory is None:
            inform_changed_data(Mediafile.objects.all())
        else:
            inform_changed_data(directory.get_children_deep())

        return Response()
Exemple #8
0
 def delete_all_speakers(self, request):
     Speaker.objects.all().delete()
     inform_changed_data(ListOfSpeakers.objects.all())
     return Response()
Exemple #9
0
    def manage_speaker(self, request, pk=None):
        """
        Special view endpoint to add users to the list of speakers or remove
        them. Send POST {'user': <user_id>} to add a new speaker.
        Send POST {'user': <user_id>, 'point_of_order': True } to add a point
        of order to the list of speakers.
        Omit data to add yourself. Send DELETE {'speaker': <speaker_id>} or
        DELETE {'speaker': [<speaker_id>, <speaker_id>, ...]} to remove one or
        more speakers from the list of speakers. Omit data to remove yourself.
        Send PATCH {'user': <user_id>, 'marked': <bool>} to mark the speaker.

        Checks also whether the requesting user can do this. He needs at
        least the permissions 'agenda.can_see_list_of_speakers' (see
        self.check_view_permissions()). In case of adding himself the
        permission 'agenda.can_be_speaker' is required. In case of adding
        or removing someone else the permission 'agenda.can_manage_list_of_speakers'
        is required. In case of removing himself no other permission is required.
        """
        # Retrieve list of speakers.
        list_of_speakers = self.get_object()

        if request.method == "POST":  # Add new speaker
            # Retrieve user_id
            user_id = request.data.get("user")
            point_of_order = request.data.get("point_of_order") or False
            if not isinstance(point_of_order, bool):
                raise ValidationError(
                    {"detail": "point_of_order has to be a bool."})

            # Check permissions and other conditions. Get user instance.
            if user_id is None:
                # Add oneself
                if not has_perm(self.request.user, "agenda.can_be_speaker"):
                    self.permission_denied(request)

                # even if the list is closed, point of order has to be accepted
                if not point_of_order and list_of_speakers.closed:
                    raise ValidationError(
                        {"detail": "The list of speakers is closed."})
                user = self.request.user
            else:
                if not isinstance(user_id, int):
                    raise ValidationError(
                        {"detail": "user_id has to be an int."})

                point_of_order = False  # not for someone else
                # Add someone else.
                if not has_perm(self.request.user,
                                "agenda.can_manage_list_of_speakers"):
                    self.permission_denied(request)
                try:
                    user = get_user_model().objects.get(pk=user_id)
                except get_user_model().DoesNotExist:
                    raise ValidationError({"detail": "User does not exist."})

            # Try to add the user. This ensurse that a user is not twice in the
            # list of coming speakers.
            try:
                speaker = Speaker.objects.add(user,
                                              list_of_speakers,
                                              point_of_order=point_of_order)
            except OpenSlidesError as e:
                raise ValidationError({"detail": str(e)})

            # Send new speaker via autoupdate because users without permission
            # to see users may not have it but can get it now.
            inform_changed_data(user, disable_history=True)

        # Set 'marked' for the speaker
        elif request.method == "PATCH":
            # Check permissions
            if not has_perm(self.request.user,
                            "agenda.can_manage_list_of_speakers"):
                self.permission_denied(request)

            # Retrieve user_id
            user_id = request.data.get("user")
            try:
                user = get_user_model().objects.get(pk=int(user_id))
            except (ValueError, get_user_model().DoesNotExist):
                raise ValidationError({"detail": "User does not exist."})

            marked = request.data.get("marked")
            if not isinstance(marked, bool):
                raise ValidationError({"detail": "Marked has to be a bool."})

            queryset = Speaker.objects.filter(
                list_of_speakers=list_of_speakers, user=user, begin_time=None)

            if not queryset.exists():
                raise ValidationError(
                    {"detail": "The user is not in the list of speakers."})
            for speaker in queryset.all():
                speaker.marked = marked
                speaker.save()

        else:
            # request.method == 'DELETE'
            speaker_ids = request.data.get("speaker")

            # Check permissions and other conditions. Get speaker instance.
            if speaker_ids is None:
                point_of_order = request.data.get("point_of_order") or False
                if not isinstance(point_of_order, bool):
                    raise ValidationError(
                        {"detail": "point_of_order has to be a bool."})
                # Remove oneself
                queryset = Speaker.objects.filter(
                    list_of_speakers=list_of_speakers,
                    user=self.request.user,
                    point_of_order=point_of_order,
                ).exclude(weight=None)

                if not queryset.exists():
                    raise ValidationError(
                        {"detail": "The user is not in the list of speakers."})
                # We delete all() from the queryset and do not use get():
                # The Speaker.objects.add method should assert, that there
                # is only one speaker. But due to race conditions, sometimes
                # there are multiple ones. Using all() ensures, that there is
                # no server crash, if this happens.
                queryset.all().delete()
                inform_changed_data(list_of_speakers)
            else:
                # Remove someone else.
                if not has_perm(self.request.user,
                                "agenda.can_manage_list_of_speakers"):
                    self.permission_denied(request)
                if isinstance(speaker_ids, int):
                    speaker_ids = [speaker_ids]
                deleted_some_speakers = False
                for speaker_id in speaker_ids:
                    try:
                        speaker = Speaker.objects.get(pk=int(speaker_id))
                    except (ValueError, Speaker.DoesNotExist):
                        pass
                    else:
                        speaker.delete(skip_autoupdate=True)
                        deleted_some_speakers = True
                # send autoupdate if speakers are deleted
                if deleted_some_speakers:
                    inform_changed_data(list_of_speakers)

        return Response()
Exemple #10
0
 def reset(self, request, pk):
     poll = self.get_object()
     poll.reset()
     return Response()
Exemple #11
0
    def manage_speaker(self, request, pk=None):
        """
        Special view endpoint to add users to the list of speakers or remove
        them. Send POST {'user': <user_id>} to add a new speaker. Omit
        data to add yourself. Send DELETE {'speaker': <speaker_id>} or
        DELETE {'speaker': [<speaker_id>, <speaker_id>, ...]} to remove one or
        more speakers from the list of speakers. Omit data to remove yourself.
        Send PATCH {'user': <user_id>, 'marked': <bool>} to mark the speaker.

        Checks also whether the requesting user can do this. He needs at
        least the permissions 'agenda.can_see_list_of_speakers' (see
        self.check_view_permissions()). In case of adding himself the
        permission 'agenda.can_be_speaker' is required. In case of adding
        or removing someone else the permission 'agenda.can_manage_list_of_speakers'
        is required. In case of removing himself no other permission is required.
        """
        # Retrieve list of speakers.
        list_of_speakers = self.get_object()

        if request.method == "POST":  # Add new speaker
            # Retrieve user_id
            user_id = request.data.get("user")

            # Check permissions and other conditions. Get user instance.
            if user_id is None:
                # Add oneself
                if not has_perm(self.request.user, "agenda.can_be_speaker"):
                    self.permission_denied(request)
                if list_of_speakers.closed:
                    raise ValidationError({"detail": "The list of speakers is closed."})
                user = self.request.user
            else:
                # Add someone else.
                if not has_perm(
                    self.request.user, "agenda.can_manage_list_of_speakers"
                ):
                    self.permission_denied(request)
                try:
                    user = get_user_model().objects.get(pk=int(user_id))
                except (ValueError, get_user_model().DoesNotExist):
                    raise ValidationError({"detail": "User does not exist."})

            # Try to add the user. This ensurse that a user is not twice in the
            # list of coming speakers.
            try:
                speaker = Speaker.objects.add(user, list_of_speakers)
            except OpenSlidesError as e:
                raise ValidationError({"detail": str(e)})

            # Send new speaker via autoupdate because users without permission
            # to see users may not have it but can get it now.
            inform_changed_data(user, disable_history=True)

        # Toggle 'marked' for the speaker
        elif request.method == "PATCH":
            # Check permissions
            if not has_perm(self.request.user, "agenda.can_manage_list_of_speakers"):
                self.permission_denied(request)

            # Retrieve user_id
            user_id = request.data.get("user")
            try:
                user = get_user_model().objects.get(pk=int(user_id))
            except (ValueError, get_user_model().DoesNotExist):
                raise ValidationError({"detail": "User does not exist."})

            marked = request.data.get("marked")
            if not isinstance(marked, bool):
                raise ValidationError({"detail": "Marked has to be a bool."})

            queryset = Speaker.objects.filter(
                list_of_speakers=list_of_speakers, user=user, begin_time=None
            )
            try:
                # We assume that there aren't multiple entries for speakers that
                # did not yet begin to speak, because this
                # is forbidden by the Manager's add method. We assume that
                # there is only one speaker instance or none.
                speaker = queryset.get()
            except Speaker.DoesNotExist:
                raise ValidationError(
                    {"detail": "The user is not in the list of speakers."}
                )
            else:
                speaker.marked = marked
                speaker.save()

        else:
            # request.method == 'DELETE'
            speaker_ids = request.data.get("speaker")

            # Check permissions and other conditions. Get speaker instance.
            if speaker_ids is None:
                # Remove oneself
                queryset = Speaker.objects.filter(
                    list_of_speakers=list_of_speakers, user=self.request.user
                ).exclude(weight=None)
                try:
                    # We assume that there aren't multiple entries because this
                    # is forbidden by the Manager's add method. We assume that
                    # there is only one speaker instance or none.
                    speaker = queryset.get()
                except Speaker.DoesNotExist:
                    raise ValidationError(
                        {"detail": "You are not on the list of speakers."}
                    )
                else:
                    speaker.delete()
            else:
                # Remove someone else.
                if not has_perm(
                    self.request.user, "agenda.can_manage_list_of_speakers"
                ):
                    self.permission_denied(request)
                if isinstance(speaker_ids, int):
                    speaker_ids = [speaker_ids]
                deleted_speaker_count = 0
                for speaker_id in speaker_ids:
                    try:
                        speaker = Speaker.objects.get(pk=int(speaker_id))
                    except (ValueError, Speaker.DoesNotExist):
                        pass
                    else:
                        speaker.delete(skip_autoupdate=True)
                        deleted_speaker_count += 1
                # send autoupdate if speakers are deleted
                if deleted_speaker_count > 0:
                    inform_changed_data(list_of_speakers)

        return Response()
Exemple #12
0
    def manage_speaker(self, request, pk=None):
        """
        Special view endpoint to add users to the list of speakers or remove
        them. Send POST {'user': <user_id>} to add a new speaker. Omit
        data to add yourself. Send DELETE {'speaker': <speaker_id>} or
        DELETE {'speaker': [<speaker_id>, <speaker_id>, ...]} to remove one or
        more speakers from the list of speakers. Omit data to remove yourself.

        Checks also whether the requesting user can do this. He needs at
        least the permissions 'agenda.can_see' (see
        self.check_view_permissions()). In case of adding himself the
        permission 'agenda.can_be_speaker' is required. In case of adding
        someone else the permission 'agenda.can_manage' is required. In
        case of removing someone else 'agenda.can_manage' is required. In
        case of removing himself no other permission is required.
        """
        # Retrieve item.
        item = self.get_object()

        if request.method == 'POST':
            # Retrieve user_id
            user_id = request.data.get('user')

            # Check permissions and other conditions. Get user instance.
            if user_id is None:
                # Add oneself
                if not self.request.user.has_perm('agenda.can_be_speaker'):
                    self.permission_denied(request)
                if item.speaker_list_closed:
                    raise ValidationError({'detail': _('The list of speakers is closed.')})
                user = self.request.user
            else:
                # Add someone else.
                if not self.request.user.has_perm('agenda.can_manage'):
                    self.permission_denied(request)
                try:
                    user = get_user_model().objects.get(pk=int(user_id))
                except (ValueError, get_user_model().DoesNotExist):
                    raise ValidationError({'detail': _('User does not exist.')})

            # Try to add the user. This ensurse that a user is not twice in the
            # list of coming speakers.
            try:
                Speaker.objects.add(user, item)
            except OpenSlidesError as e:
                raise ValidationError({'detail': str(e)})
            message = _('User %s was successfully added to the list of speakers.') % user

        else:
            # request.method == 'DELETE'
            speaker_ids = request.data.get('speaker')

            # Check permissions and other conditions. Get speaker instance.
            if speaker_ids is None:
                # Remove oneself
                queryset = Speaker.objects.filter(
                    item=item, user=self.request.user).exclude(weight=None)
                try:
                    # We assume that there aren't multiple entries because this
                    # is forbidden by the Manager's add method. We assume that
                    # there is only one speaker instance or none.
                    speaker = queryset.get()
                except Speaker.DoesNotExist:
                    raise ValidationError({'detail': _('You are not on the list of speakers.')})
                else:
                    speaker.delete()
                    message = _('You are successfully removed from the list of speakers.')
            else:
                # Remove someone else.
                if not self.request.user.has_perm('agenda.can_manage'):
                    self.permission_denied(request)
                if type(speaker_ids) is int:
                    speaker_ids = [speaker_ids]
                for speaker_id in speaker_ids:
                    try:
                        speaker = Speaker.objects.get(pk=int(speaker_id))
                    except (ValueError, Speaker.DoesNotExist):
                        raise ValidationError({'detail': _('Speaker does not exist.')})
                    # Delete the speaker.
                    speaker.delete()
                    message = _('Speaker %s was successfully removed from the list of speakers.') % speaker

        # Initiate response.
        return Response({'detail': message})