Beispiel #1
0
    def list(self, request, *args, **kwargs):
        query = request.query_params
        if 'document_id' not in query:
            return Response({'detail': 'document_id is required'}, status=400)

        document_id = int(query['document_id'])
        document = get_object_or_404(Document,
                                     account=self.get_current_account(),
                                     pk=document_id)
        if PERMISSIONS.view not in get_object_permissions(
                self.get_current_membership(), document):
            raise PermissionDenied("No view permission for document %d" %
                                   document_id)

        queryset = Annotation.objects.filter(document_id=document_id)\
            .filter(Q(author_user=request.user) | Q(shared=True))

        if 'from_page' in query:
            queryset = queryset.filter(document_page__gte=query['from_page'])
        if 'to_page' in query:
            queryset = queryset.filter(document_page__lte=query['to_page'])

        annotations = list(queryset)

        serializer = AnnotationUpdateSerializer(
            {
                'document_id': document_id,
                'annotations': annotations,
            },
            context=self.get_serializer_context())

        return Response(serializer.data)
    def create(self, validated_data):
        context = self.context
        document = get_object_or_404(Document, account=context['account'], pk=validated_data['document_id'])
        permissions = get_object_permissions(context['membership'], document)
        if PERMISSIONS.view not in permissions:
            raise PermissionDenied("No view permission for document %d" % document.id)

        notes = []
        deleted_annotations = []
        annotations_query = document.annotations.prefetch_related('comments')
        user_annotations = {a.id: a for a in annotations_query.filter(author_user=context['user'])}
        shared_annotations = {a.id: a for a in annotations_query.filter(shared=True) if a.id not in user_annotations}
        if 'annotation_id_to_delete' in validated_data:
            for annotation_id in validated_data['annotation_id_to_delete']:
                if annotation_id not in user_annotations:
                    notes.append("Can't delete annotation with id=%d as it doesn't belong to current user or document" % annotation_id)
                else:
                    user_annotations[annotation_id].delete()
                    del user_annotations[annotation_id]
                    deleted_annotations.append(annotation_id)

        result_annotations = []
        for annotation in validated_data['annotations']:
            try:
                if 'id' in annotation:
                    if annotation['id'] in user_annotations:
                        s = AnnotationSerializer(user_annotations[annotation['id']], data=annotation, context=context)
                    elif annotation['id'] in shared_annotations:
                        # Only comments can be updated, so: get data as it is in DB + change comments
                        readonly_context = copy(context)
                        readonly_context['readonly'] = True
                        aa = AnnotationSerializer(shared_annotations[annotation['id']], context=readonly_context).data
                        aa['comments'] = annotation.get('comments', [])
                        s = AnnotationSerializer(shared_annotations[annotation['id']], data=aa, context=readonly_context)
                    else:
                        raise ValidationError({
                            'detail': "Can't update annotation with id=%d which doesn't belong to current user or document." % annotation['id']})
                else:
                    s = AnnotationSerializer(data=annotation, context=context)

                s.is_valid(raise_exception=True)
                s.save(author_user=context['user'], account=context['account'], document=document)
                result_annotations.append(s.instance)
            except ValidationError as e:
                notes.append(e.detail['detail'])

        return {
            'document_id': validated_data['document_id'],
            'annotations': result_annotations,
            'annotation_id_to_delete': deleted_annotations,
            'notes': notes,
        }
Beispiel #3
0
 def require_folder_permission(self, permission, folder=None):
     if permission not in get_object_permissions(
             self.get_current_membership(), folder or self.folder):
         raise PermissionDenied(
             "You don't have %s permission for this folder" %
             (permission, ))
Beispiel #4
0
    def get_meeting_details(meeting, queryset, for_user, account, for_date):
        """
        Method is extracted into static to be reused for REST serializer
        """
        context = OrderedDict()
        # next/previous meeting
        previous_meeting = queryset.filter(start__lte=meeting.start).exclude(id=meeting.id).order_by('-start')
        next_meeting = queryset.filter(start__gt=meeting.start).exclude(id=meeting.id).order_by('start')
        context['next'] = next_meeting[0] if next_meeting else None
        context['previous'] = previous_meeting[0] if previous_meeting else None

        # members_email
        membership = for_user.get_membership(account)
        permissions = get_object_permissions(membership, meeting)

        if meeting.committee:
            context['members_email'] = mailto_email((meeting.committee,))
        else:
            members_email = 'mailto:'
            for member in meeting.account.memberships.all():
                if member.user.email not in members_email:
                    members_email += '{},'.format(member.user.email)
            context['members_email'] = members_email[:-1]

        # if the user is assistant to board member, then we should use boss data
        boss_users = [boss.user for boss in membership.get_bosses()]

        # rsvp
        repetition = None
        if for_date:
            try:
                date = dateutil.parser.parse(for_date)

                repetition = meeting.repetitions.filter(date=date).get()
            except (MeetingRepetition.DoesNotExist, ValueError):
                pass

        if repetition is None:
            repetition = meeting.closest_repetition

        assert isinstance(repetition, MeetingRepetition)

        # Query and process the RSVP responses
        # Implementation note: pull all RSVP records for this meeting from the database in one query.
        # Processing into current and historical RSVP data is done in python because it's faster than chatty DB queries.
        rsvp_for_all_repetitions = meeting.rsvp_responses.filter(user__is_active=True, meeting_repetition=None) \
            .order_by("timestamp") \
            .select_related("user")
        rsvp_for_repetition = repetition.rsvp_responses.filter(user__is_active=True) \
            .order_by("timestamp") \
            .select_related("user")
        rsvp_by_user = {}
        meeting_members = meeting.members
        meeting_members_by_user_id = {m.user.id: m for m in meeting_members}

        rsvp = sorted(list(rsvp_for_all_repetitions) + list(rsvp_for_repetition), key=lambda r: r.timestamp)

        for r in rsvp:
            if r.user.pk not in meeting_members_by_user_id:
                # Filter out situation where user rsvped and then was removed from members for meeting.
                continue

            obj = {
                "timestamp": r.timestamp,
                "user_id": r.user.pk,
                "name": r.user.get_full_name(),
                "email": r.user.email,
                "is_attending": r.response == RsvpResponse.ACCEPT,
                "attending": r.get_response_display(),
                "accept_type": r.accept_type,
                "accept_type_display": r.get_accept_type_display(),
                "note": r.note,
                "is_invited": meeting_members_by_user_id[r.user.pk].is_meeting_member_invited,
                "icon": (r.response == RsvpResponse.ACCEPT) and "check.png" or
                        (r.response == RsvpResponse.DECLINE) and "cancel.png" or "question.png",
            }
            if r.user.pk in rsvp_by_user:
                rsvp_by_user[r.user.pk].append(obj)
            else:
                rsvp_by_user[r.user.pk] = [obj]

        # Also include pseudo-rsvp-responses for the users who did not respond to the RSVP
        no_rsvp = [m for m in meeting_members if m.user.id not in rsvp_by_user.keys()]
        for r in no_rsvp:
            obj = {
                "timestamp": timezone.now(),
                "user_id": r.user.pk,
                "name": r.user.get_full_name(),
                "email": r.user.email,
                "is_attending": False,
                "attending": _('No reply'),
                "is_invited": r.is_meeting_member_invited,
                "icon": "question.png",
            }
            rsvp_by_user[r.user.pk] = [obj]

        context["rsvp_responses"] = [user_responses[-1] for user_responses in rsvp_by_user.values()]
        for r in context["rsvp_responses"]:
            r["history"] = rsvp_by_user.get(r["user_id"], [])[:-1]
        context["rsvp_responses"] = sorted(context["rsvp_responses"], key=lambda r: r["name"])

        context["rsvp_attendance"] = len([r for r in context["rsvp_responses"] if r["is_attending"]])

        context["current_repetition"] = repetition
        fill_rsvp_responses([repetition], for_user if len(boss_users) == 0 else boss_users[0])

        future_repetitions = meeting.future_repetitions()[:10]
        if meeting.repeat_type:
            fill_rsvp_responses(future_repetitions, for_user if len(boss_users) == 0 else boss_users[0])
            # and [m for m in meeting_members if m.user_id == for_user.id]:
            # fill_rsvp_responses(future_repetitions, for_user)

        context["future_repetitions"] = future_repetitions

        # Add actual attendance records
        context['record_attendance'] = False

        if membership.is_admin and meeting.start < timezone.now():
            context['record_attendance'] = True
            context['attendance_choice'] = MeetingAttendance.PRESENT_TYPES

        ma_values = MeetingAttendance.objects.filter(meeting=meeting).values("user_id", "present")
        ma = {x["user_id"]: x["present"] for x in ma_values}

        for r in context["rsvp_responses"]:
            r["present"] = ma.get(r["user_id"], None)

        # get calendar connections
        context['has_social_connections'] = False
        context['is_google_connected'] = False
        context['is_office_connected'] = False
        context['is_ical_connected'] = False

        cal_connections = CalendarConnection.objects.filter(account=account)
        for conn in cal_connections:
            context['has_social_connections'] = True
            if conn.provider == 'google':
                context['is_google_connected'] = True
                context['checked_google_add'] = conn.checked_add

            if conn.provider == 'office':
                context['is_office_connected'] = True
                context['checked_office_add'] = conn.checked_add

            if conn.provider == 'ical':
                context['is_ical_connected'] = True
                context['checked_ical_add'] = conn.checked_add

        # approved documents list
        agenda = meeting.get_agenda()
        context['agenda_approved'] = list(agenda.approved_user_ids() if agenda else [])
        context['any_approved'] = set(context['agenda_approved'])
        bbook = meeting.get_board_book()
        context['boardbook_approved'] = list(bbook.approved_user_ids() if bbook else [])
        context['any_approved'].update(context['boardbook_approved'])
        minutes = meeting.get_minutes()
        context['minutes_approved'] = list(minutes.approved_user_ids() if minutes else [])
        context['any_approved'].update(context['minutes_approved'])

        return context
 def has_object_permission(self, request, view, obj):
     return request.user.is_authenticated \
            and PERMISSIONS.edit in get_object_permissions(request.user.get_membership(get_current_account(request)), obj)