Пример #1
0
 def notify_subscribers():
     push_notification(
         list(instance.topic.subscribers.exclude(pk=instance.user.pk)),
         instance.user, 'new_forum_reply', {
             'user':
             instance.user.userprofile.get_display_name(),
             'user_url':
             settings.BASE_URL +
             reverse_url('user_page', kwargs={'username': instance.user}),
             'post_url':
             build_notification_url(
                 settings.BASE_URL + instance.get_absolute_url(),
                 instance.user),
             'topic_url':
             build_notification_url(
                 settings.BASE_URL + instance.topic.get_absolute_url(),
                 instance.user),
             'topic_name':
             instance.topic.name,
             'unsubscribe_url':
             build_notification_url(
                 settings.BASE_URL + reverse_url('pybb:delete_subscription',
                                                 args=[instance.topic.id]),
                 instance.user)
         })
Пример #2
0
def forum_topic_pre_save(sender, instance, **kwargs):
    if not hasattr(instance.forum, 'group'):
        return

    try:
        topic = sender.objects.get(pk=instance.pk)
    except sender.DoesNotExist:
        pass
    else:
        if topic.on_moderation == True and instance.on_moderation == False:
            # This topic is being approved
            group = instance.forum.group
            push_notification(
                [x for x in group.members.all() if x != instance.user],
                instance.user,
                'new_topic_in_group',
                {
                    'user':
                    instance.user.userprofile.get_display_name(),
                    'url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.user),
                    'group_url':
                    build_notification_url(
                        reverse_url('group_detail', kwargs={'pk': group.pk}),
                        instance.user),
                    'group_name':
                    group.name,
                    'topic_title':
                    instance.name,
                },
            )
Пример #3
0
    def notify_subscribers(mentions):
        # type: (List[str]) -> None
        recipients = list(
            instance.topic.subscribers.exclude(pk__in=list(
                set([instance.user.pk] + [
                    x.pk for x in MentionsService.
                    get_mentioned_users_with_notification_enabled(
                        mentions, 'new_forum_post_mention')
                ]))))

        if recipients:
            push_notification(
                recipients, instance.user, 'new_forum_reply', {
                    'user':
                    instance.user.userprofile.get_display_name(),
                    'user_url':
                    settings.BASE_URL + reverse_url(
                        'user_page', kwargs={'username': instance.user}),
                    'post_url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.user),
                    'topic_url':
                    build_notification_url(
                        settings.BASE_URL + instance.topic.get_absolute_url(),
                        instance.user),
                    'topic_name':
                    instance.topic.name,
                    'unsubscribe_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse_url('pybb:delete_subscription',
                                    args=[instance.topic.id]), instance.user)
                })
    def reject(self, request, pk):
        edit_proposal: EquipmentItemEditProposalMixin = get_object_or_404(
            self.get_serializer().Meta.model, pk=pk)

        check_permissions, response = self.check_edit_proposal_permissions(
            request, edit_proposal)
        if not check_permissions:
            return response

        edit_proposal.edit_proposal_reviewed_by = request.user
        edit_proposal.edit_proposal_review_ip = request.META.get('REMOTE_ADDR')
        edit_proposal.edit_proposal_review_timestamp = timezone.now()
        edit_proposal.edit_proposal_review_comment = request.data.get(
            'comment')
        edit_proposal.edit_proposal_review_status = 'REJECTED'

        edit_proposal.save()

        target = edit_proposal.edit_proposal_target

        push_notification(
            [
                x for x in list(
                    {edit_proposal.edit_proposal_by, target.created_by})
                if x != request.user
            ], request.user, 'equipment-edit-proposal-rejected', {
                'user':
                request.user.userprofile.get_display_name(),
                'user_url':
                build_notification_url(
                    settings.BASE_URL +
                    reverse('user_page', args=(request.user.username, ))),
                'item':
                f'{target.brand.name if target.brand else _("(DIY)")} {target.name}',
                'item_url':
                build_notification_url(
                    AppRedirectionService.redirect(
                        f'/equipment'
                        f'/explorer'
                        f'/{target.item_type}/{target.pk}'
                        f'/{target.slug}')),
                'edit_proposal_url':
                build_notification_url(
                    AppRedirectionService.redirect(
                        f'/equipment'
                        f'/explorer'
                        f'/{target.item_type}/{target.pk}'
                        f'/{target.slug}'
                        f'/edit-proposals'
                        f'/{edit_proposal.pk}/')),
                'comment':
                edit_proposal.edit_proposal_review_comment
            })

        serializer = self.serializer_class(edit_proposal)
        return Response(serializer.data)
Пример #5
0
    def reject(self, request, pk):
        if not request.user.groups.filter(name='equipment_moderators').exists():
            raise PermissionDenied(request.user)

        strategy: GearMigrationStrategy = self.get_object()

        if strategy.migration_flag is None:
            return Response(status=409)

        if request.user == strategy.migration_flag_moderator:
            raise PermissionDenied

        target = strategy.migration_content_object

        push_notification(
            [strategy.migration_flag_moderator],
            request.user,
            'equipment-item-migration-rejected',
            {
                'user': request.user.userprofile.get_display_name(),
                'user_url': build_notification_url(
                    settings.BASE_URL + reverse('user_page', args=(request.user.username,))
                ),
                'migration_flag': strategy.migration_flag,
                'reason': request.data.get('reason'),
                'comment': request.data.get('comment'),
                'legacy_item': strategy.gear,
                'target_item': f'{target.brand.name if target.brand else _("(DIY)")} {target.name}' if target else None,
                'target_url': build_notification_url(
                    AppRedirectionService.redirect(
                        f'/equipment'
                        f'/explorer'
                        f'/{target.item_type}/{target.pk}'
                        f'/{target.slug}'
                    )
                ) if target else None,
                'migration_tool_url': build_notification_url(
                    AppRedirectionService.redirect(
                        f'/equipment'
                        f'/migration-tool'
                    )
                ) if target else None,
            }
        )

        strategy.gear.migration_flag_moderator_lock = None
        strategy.gear.migration_flag_moderator_lock_timestamp = None
        strategy.gear.save()

        strategy.delete()

        serializer = self.get_serializer(strategy)
        return Response(serializer.data)
Пример #6
0
def solution_post_save(sender, instance, created, **kwargs):
    ct = instance.content_type

    try:
        target = ct.get_object_for_this_type(pk=instance.object_id)
    except ct.model_class().DoesNotExist:
        return

    if ct.model == 'image':
        user = target.user
    elif ct.model == 'imagerevision':
        user = target.image.user
    else:
        return

    if instance.status == Solver.FAILED:
        notification = 'image_not_solved'
    elif instance.status == Solver.SUCCESS:
        notification = 'image_solved'
    else:
        return

    push_notification(
        [user], None, notification, {
            'object_url':
            build_notification_url(settings.BASE_URL +
                                   target.get_absolute_url())
        })
Пример #7
0
def nested_comment_post_save(sender, instance, created, **kwargs):
    if created:
        mentions = MentionsService.get_mentions(instance.text)

        CommentNotificationsService(instance).send_notifications()

        if hasattr(instance.content_object, "updated"):
            # This will trigger the auto_now fields in the content_object
            # We do it only if created, because the content_object needs to
            # only be updated if the number of comments changes.
            instance.content_object.save(keep_deleted=True)

        if instance.pending_moderation:
            CommentNotificationsService.send_moderation_required_email()
    else:
        mentions = cache.get(
            "user.%d.comment_pre_save_mentions" % instance.author.pk, [])

    for username in mentions:
        try:
            user = User.objects.get(username=username)
            push_notification(
                [user], instance.author, 'new_comment_mention', {
                    'url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.author),
                    'user':
                    instance.author.userprofile.get_display_name(),
                    'user_url':
                    settings.BASE_URL + reverse_url(
                        'user_page', kwargs={'username': instance.author}),
                })
        except User.DoesNotExist:
            pass
Пример #8
0
 def notify_mentioned(mentions):
     # type: (List[str]) -> None
     for username in mentions:
         user = get_object_or_None(User, username=username)
         if user is None:
             try:
                 profile = get_object_or_None(UserProfile,
                                              real_name=username)
                 if profile:
                     user = profile.user
             except MultipleObjectsReturned:
                 user = None
         if user:
             push_notification(
                 [user], instance.user, 'new_forum_post_mention', {
                     'url':
                     build_notification_url(
                         settings.BASE_URL + instance.get_absolute_url(),
                         instance.user),
                     'user':
                     instance.user.userprofile.get_display_name(),
                     'user_url':
                     settings.BASE_URL + reverse_url(
                         'user_page', kwargs={'username': instance.user}),
                     'post':
                     instance.topic.name,
                 })
Пример #9
0
    def post(self, request, *args, **kwargs):
        group = self.get_object()
        for pk in request.POST.getlist('users[]'):
            try:
                user = UserProfile.objects.get(user__pk=pk).user
            except UserProfile.DoesNotExist:
                continue

            group.invited_users.add(user)
            push_notification(
                [user], request.user, 'new_group_invitation',
                {
                    'inviter': request.user.userprofile.get_display_name(),
                    'inviter_page': reverse('user_page', args=(request.user.username,)),
                    'group_name': group.name,
                    'group_page': build_notification_url(
                        settings.BASE_URL + reverse('group_detail', args=(group.pk, group.slug)), request.user),
                })

        if request.is_ajax():
            return self.render_json_response({
                'invited_users': [{
                    'id': x.id,
                    'username': x.username,
                    'display_name': x.userprofile.get_display_name(),
                    'url': reverse('user_page', args=(x.username,)),
                    'revoke_url': reverse('group_revoke_invitation', args=(group.pk,)),
                } for x in group.invited_users.all()]
            })

        return redirect(self.get_success_url())
Пример #10
0
def push_notification_for_group_join_request_rejection(group_pk, user_pk, moderator_pk):
    try:
        group = Group.objects.get(pk=group_pk)
    except Group.DoesNotExist:
        logger.warning('push_notification_for_group_join_request_rejection: group not found: %d' % group_pk)
        return

    try:
        user = User.objects.get(pk=user_pk)
    except User.DoesNotExist:
        logger.warning('push_notification_for_group_join_request_rejection: user not found: %d' % user_pk)
        return

    try:
        moderator = User.objects.get(pk=moderator_pk)
    except User.DoesNotExist:
        logger.warning('push_notification_for_group_join_request_rejection: moderator not found: %d' % moderator_pk)
        return

    push_notification(
        [user], moderator, 'group_join_request_rejected',
        {
            'group_name': group.name,
            'url': build_notification_url(
                settings.BASE_URL + reverse('group_detail', args=(group.pk,)), moderator
            ),
        })
    def send_notifications(self, force=False):
        if self.comment.pending_moderation and not force:
            return

        instance = self.comment

        model_class = instance.content_type.model_class()
        obj = instance.content_type.get_object_for_this_type(id=instance.object_id)
        url = settings.BASE_URL + instance.get_absolute_url()

        if model_class == Image:
            if UserService(obj.user).shadow_bans(instance.author):
                log.info("Skipping notification for comment because %d shadow-bans %d" % (
                    obj.user.pk, instance.author.pk))
                return

            if instance.parent and \
                    instance.parent.author != instance.author and \
                    not instance.pending_moderation:
                push_notification(
                    [instance.parent.author], instance.author, 'new_comment_reply',
                    {
                        'url': build_notification_url(url, instance.author),
                        'user': instance.author.userprofile.get_display_name(),
                        'user_url': settings.BASE_URL + reverse(
                            'user_page', kwargs={'username': instance.author.username}),
                    }
                )

            if instance.author != obj.user and \
                    (instance.parent is None or instance.parent.author != obj.user) and \
                    not instance.pending_moderation:
                push_notification(
                    [obj.user], instance.author, 'new_comment',
                    {
                        'url': build_notification_url(url, instance.author),
                        'user': instance.author.userprofile.get_display_name(),
                        'user_url': settings.BASE_URL + reverse(
                            'user_page', kwargs={'username': instance.author.username}),
                    }
                )

            if (force or not instance.pending_moderation) and not obj.is_wip:
                add_story(instance.author,
                          verb='VERB_COMMENTED_IMAGE',
                          action_object=instance,
                          target=obj)
 def send_approval_notification(self):
     if not self.comment.pending_moderation:
         push_notification(
             [self.comment.author], None, 'comment_approved', {
                 'url':
                 build_notification_url(settings.BASE_URL +
                                        self.comment.get_absolute_url())
             })
Пример #13
0
    def reject(self, request, pk):
        model = self.get_serializer().Meta.model
        item: EquipmentItem = get_object_or_404(model.objects, pk=pk)

        if item.reviewed_by is not None and item.reviewer_decision == 'APPROVED':
            return Response("This item was already approved",
                            HTTP_400_BAD_REQUEST)

        if item.created_by == request.user:
            return Response("You cannot review an item that you created",
                            HTTP_400_BAD_REQUEST)

        item.reviewed_by = request.user
        item.reviewed_timestamp = timezone.now()
        item.reviewer_decision = 'REJECTED'
        item.reviewer_rejection_reason = request.data.get('reason')
        item.reviewer_comment = request.data.get('comment')

        if item.created_by:
            push_notification(
                [item.created_by], request.user, 'equipment-item-rejected', {
                    'user':
                    request.user.userprofile.get_display_name(),
                    'user_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse('user_page', args=(request.user.username, ))),
                    'item':
                    f'{item.brand.name} {item.name}',
                    'reject_reason':
                    item.reviewer_rejection_reason,
                    'comment':
                    item.reviewer_comment,
                })

        item.name = '[DELETED] %s' % item.name
        item.save()
        item.delete()

        Gear.objects.filter(
            migration_flag='MIGRATE',
            migration_content_type=ContentType.objects.get_for_model(model),
            migration_object_id=item.id,
        ).update(
            migration_flag=None,
            migration_content_type=None,
            migration_object_id=None,
            migration_flag_moderator=None,
            migration_flag_moderator_lock=None,
            migration_flag_moderator_lock_timestamp=None,
            migration_flag_reviewer=None,
            migration_flag_reviewer_decision='REJECTED_BAD_MIGRATION_TARGET',
            migration_flag_reviewer_rejection_comment=request.data.get(
                'comment'))

        serializer = self.serializer_class(item)
        return Response(serializer.data)
Пример #14
0
def push_notification_for_new_image_revision(revision_pk):
    try:
        revision = ImageRevision.objects.get(pk=revision_pk)
    except ImageRevision.DoesNotExist:
        logger.error('push_notification_for_new_image called for revision not found: %d' % revision_pk)
        return

    if revision.skip_notifications or revision.image.is_wip:
        logger.error('push_notification_for_new_image called for revision of image that is wip: %d' % revision_pk)
        return

    followers = [x.user for x in ToggleProperty.objects.filter(
        property_type="follow",
        content_type=ContentType.objects.get_for_model(User),
        object_id=revision.image.user.pk)]

    if len(followers) > 0:
        previous_revision = ImageRevision.objects \
            .filter(image=revision.image) \
            .exclude(pk=revision.pk) \
            .order_by('-uploaded').first()

        thumb = revision.thumbnail_raw('gallery', sync=True)

        push_notification(followers, revision.image.user, 'new_image_revision', {
            'url': build_notification_url(settings.BASE_URL + revision.get_absolute_url(), revision.image.user),
            'user_url': build_notification_url(
                settings.BASE_URL + revision.image.user.userprofile.get_absolute_url(), revision.image.user),
            'user': revision.image.user.userprofile.get_display_name(),
            'image_title': revision.image.title,
            'title': revision.title,
            'description': revision.description,
            'previous_update_date': formats.date_format(max(
                revision.image.published,
                previous_revision.uploaded if previous_revision is not None else datetime.min
            ), "DATE_FORMAT"),
            'image_thumbnail': thumb.url if thumb else None,
        })
    else:
        logger.info(
            'push_notification_for_new_image called for revision %d whose author has no followers' % revision_pk
        )
Пример #15
0
 def send_moderation_required_notification(self):
     if self.comment.pending_moderation:
         ct = ContentType.objects.get_for_id(self.comment.content_type_id)
         if ct.model == 'image':
             image = self.comment.content_object
             push_notification([image.user], None, 'new_image_comment_moderation', {
                 'title': image.title,
                 'url': build_notification_url(
                     '%s%s#c%d' % (settings.BASE_URL, image.get_absolute_url(), self.comment.pk),
                     additional_query_args={'moderate-comment': 1})
             })
Пример #16
0
    def approve(self, request, pk):
        item = get_object_or_404(self.get_serializer().Meta.model.objects,
                                 pk=pk)

        if item.reviewed_by is not None:
            return Response("This item was already reviewed",
                            HTTP_400_BAD_REQUEST)

        if item.created_by == request.user:
            return Response("You cannot review an item that you created",
                            HTTP_400_BAD_REQUEST)

        item.reviewed_by = request.user
        item.reviewed_timestamp = timezone.now()
        item.reviewer_decision = 'APPROVED'
        item.reviewer_comment = request.data.get('comment')

        if item.created_by:
            push_notification(
                [item.created_by], request.user, 'equipment-item-approved', {
                    'user':
                    request.user.userprofile.get_display_name(),
                    'user_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse('user_page', args=(request.user.username, ))),
                    'item':
                    f'{item.brand.name} {item.name}',
                    'item_url':
                    build_notification_url(
                        AppRedirectionService.redirect(
                            f'/equipment/explorer/{EquipmentItemService(item).get_type()}/{item.pk}'
                        )),
                    'comment':
                    item.reviewer_comment,
                })

        item.save()

        serializer = self.serializer_class(item)
        return Response(serializer.data)
Пример #17
0
def forum_topic_post_save(sender, instance, created, **kwargs):
    if created and hasattr(instance.forum, 'group'):
        group = instance.forum.group

        if instance.on_moderation:
            recipients = group.moderators.all()
        else:
            recipients = group.members.all()
        recipients = [x for x in recipients if x != instance.user]

        push_notification(
            recipients,
            instance.user,
            'new_topic_in_group',
            {
                'user_url':
                build_notification_url(settings.BASE_URL + reverse_url(
                    'user_page', kwargs={'username': instance.user})),
                'user':
                instance.user.userprofile.get_display_name(),
                'url':
                build_notification_url(
                    settings.BASE_URL + instance.get_absolute_url(),
                    instance.user),
                'group_url':
                build_notification_url(
                    settings.BASE_URL +
                    reverse_url('group_detail', kwargs={'pk': group.pk}),
                    instance.user),
                'group_name':
                group.name,
                'topic_title':
                instance.name,
            },
        )

    cache_key = make_template_fragment_key(
        'home_page_latest_from_forums',
        (instance.user.pk, instance.user.userprofile.language))
    cache.delete(cache_key)
Пример #18
0
def solution_pre_save(sender, instance, **kwargs):
    try:
        solution_before_save = Solution.objects.get(pk=instance.pk)
    except Solution.DoesNotExist:
        return

    if solution_before_save.status >= instance.status:
        return

    if instance.status == Solver.FAILED:
        notification = 'image_not_solved'
    elif instance.status == Solver.SUCCESS:
        notification = 'image_solved'
    elif instance.status == Solver.ADVANCED_SUCCESS:
        notification = 'image_solved_advanced'
    elif instance.status == Solver.ADVANCED_FAILED:
        notification = 'image_not_solved_advanced'
    else:
        return

    ct = instance.content_type

    try:
        target = ct.get_object_for_this_type(pk=instance.object_id)
    except ct.model_class().DoesNotExist:
        return

    if ct.model == 'image':
        user = target.user
        title = target.title
        thumb = target.thumbnail_raw('gallery', '0', sync=True)
    elif ct.model == 'imagerevision':
        user = target.image.user
        title = target.image.title
        thumb = target.image.thumbnail_raw('gallery', target.label, sync=True)
    else:
        return

    push_notification(
        [user], None, notification, {
            'object_url':
            build_notification_url(settings.BASE_URL +
                                   target.get_absolute_url()),
            'title':
            title,
            'image_thumbnail':
            thumb.url if thumb else None,
        })
Пример #19
0
def nested_comment_post_save(sender, instance, created, **kwargs):
    if created:
        mentions = MentionsService.get_mentions(instance.text)

        if hasattr(instance.content_object, "updated"):
            # This will trigger the auto_now fields in the content_object
            # We do it only if created, because the content_object needs to
            # only be updated if the number of comments changes.
            save_kwargs = {}
            if issubclass(type(instance.content_object), SafeDeleteModel):
                save_kwargs['keep_deleted'] = True
            instance.content_object.save(**save_kwargs)

        if instance.pending_moderation:
            CommentNotificationsService(
                instance).send_moderation_required_notification()
        else:
            CommentNotificationsService(instance).send_notifications()
    else:
        mentions = cache.get(
            "user.%d.comment_pre_save_mentions" % instance.author.pk, [])

    if not instance.pending_moderation:
        for username in mentions:
            user = get_object_or_None(User, username=username)
            if not user:
                try:
                    profile = get_object_or_None(UserProfile,
                                                 real_name=username)
                    if profile:
                        user = profile.user
                except MultipleObjectsReturned:
                    user = None
            if user:
                push_notification(
                    [user], instance.author, 'new_comment_mention', {
                        'url':
                        build_notification_url(
                            settings.BASE_URL + instance.get_absolute_url(),
                            instance.author),
                        'user':
                        instance.author.userprofile.get_display_name(),
                        'user_url':
                        settings.BASE_URL + reverse_url(
                            'user_page', kwargs={'username': instance.author}),
                    })
Пример #20
0
    def handle(self, *args, **options):
        for user in User.objects.all():
            number = 0
            qs = Image.objects.filter(user=user, is_wip=False)

            number += qs.filter(
                (Q(subject_type=SubjectType.DEEP_SKY) & Q(subjects=None))
                | (Q(subject_type=SubjectType.SOLAR_SYSTEM)
                   & Q(solar_system_main_subject=None))).count()
            number += qs.filter(
                Q(imaging_telescopes=None) | Q(imaging_cameras=None)).count()
            number += qs.filter(Q(acquisition=None)).count()

            if number > 0:
                push_notification(
                    [user], None, 'lacking_data_reminder', {
                        'number':
                        number,
                        'url':
                        build_notification_url(user.get_absolute_url() +
                                               '?public&sub=nodata')
                    })
Пример #21
0
    def post(self, request, *args, **kwargs):
        group = self.get_object()

        def doAdd(user, group):
            group.members.add(user)
            group.invited_users.remove(user)
            group.join_requests.remove(user)
            messages.success(request, _("You have joined the group"))

        if request.user in group.members.all():
            messages.error(request, _("You already were a member of this group"))
            return redirect(self.get_success_url())

        if group.public:
            if group.moderated and request.user != group.owner:
                group.join_requests.add(request.user)
                messages.warning(request,
                                 _("This is a moderated group, and your join request will be reviewed by a moderator"))
                push_notification(
                    group.moderators.all(), request.user, 'new_group_join_request',
                    {
                        'requester': request.user.userprofile.get_display_name(),
                        'group_name': group.name,
                        'url': build_notification_url(
                            settings.BASE_URL + reverse('group_moderate_join_requests', args=(group.pk,)), request.user)
                    })
                return redirect(self.get_success_url())
            else:
                doAdd(request.user, group)
                return redirect(self.get_success_url())
        else:
            if request.user in group.invited_users.all() or request.user == group.owner:
                doAdd(request.user, group)
                return redirect(self.get_success_url())

        return HttpResponseForbidden()
Пример #22
0
def push_notification_for_new_image_revision(revision_pk):
    try:
        revision = ImageRevision.objects.get(pk=revision_pk)
    except ImageRevision.DoesNotExist:
        logger.error(
            'push_notification_for_new_image called for revision not found: %d'
            % revision_pk)
        return

    if revision.skip_notifications or revision.image.is_wip:
        logger.error(
            'push_notification_for_new_image called for revision of image that is wip: %d'
            % revision_pk)
        return

    followers = [
        x.user for x in ToggleProperty.objects.filter(
            property_type="follow",
            content_type=ContentType.objects.get_for_model(User),
            object_id=revision.image.user.pk)
    ]

    if len(followers) > 0:
        push_notification(
            followers, revision.image.user, 'new_image_revision', {
                'object_url':
                build_notification_url(
                    settings.BASE_URL + revision.get_absolute_url(),
                    revision.image.user),
                'originator':
                revision.image.user.userprofile.get_display_name(),
            })
    else:
        logger.error(
            'push_notification_for_new_image called for revision %d whose author has no followers'
            % revision_pk)
Пример #23
0
    def reject(self, request, pk):
        from astrobin_apps_equipment.models import Sensor
        from astrobin_apps_equipment.models import Camera
        from astrobin_apps_equipment.models import CameraEditProposal
        from astrobin_apps_equipment.models import Telescope
        from astrobin_apps_equipment.models import Mount
        from astrobin_apps_equipment.models import Filter
        from astrobin_apps_equipment.models import Accessory
        from astrobin_apps_equipment.models import Software

        model = self.get_serializer().Meta.model
        item: EquipmentItem = get_object_or_404(model.objects, pk=pk)

        if item.reviewed_by is not None and item.reviewer_decision == 'APPROVED':
            return Response("This item was already approved",
                            HTTP_400_BAD_REQUEST)

        if item.created_by == request.user:
            return Response("You cannot review an item that you created",
                            HTTP_400_BAD_REQUEST)

        item.reviewed_by = request.user
        item.reviewed_timestamp = timezone.now()
        item.reviewer_decision = 'REJECTED'
        item.reviewer_rejection_reason = request.data.get('reason')
        item.reviewer_comment = request.data.get('comment')

        if item.created_by and item.created_by != request.user:
            push_notification(
                [item.created_by], request.user, 'equipment-item-rejected', {
                    'user':
                    request.user.userprofile.get_display_name(),
                    'user_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse('user_page', args=(request.user.username, ))),
                    'item':
                    f'{item.brand.name if item.brand else _("(DIY)")} {item.name}',
                    'reject_reason':
                    item.reviewer_rejection_reason,
                    'comment':
                    item.reviewer_comment,
                })

        if item.klass == EquipmentItemKlass.SENSOR:
            Camera.all_objects.filter(sensor=item).update(sensor=None)
            CameraEditProposal.all_objects.filter(sensor=item).update(
                sensor=None)

        item.delete()

        GearMigrationStrategy.objects.filter(
            migration_flag='MIGRATE',
            migration_content_type=ContentType.objects.get_for_model(model),
            migration_object_id=item.id,
        ).delete()

        if item.brand:
            brand_has_items = False
            for klass in (Sensor, Camera, Telescope, Mount, Filter, Accessory,
                          Software):
                if klass.objects.filter(brand=item.brand).exists():
                    brand_has_items = True
                    break

            if not brand_has_items:
                item.brand.delete()

        serializer = self.serializer_class(item)
        return Response(serializer.data)
Пример #24
0
    def send_notifications(self, force=False):
        if self.comment.pending_moderation and not force:
            return

        instance = self.comment

        model_class = instance.content_type.model_class()
        obj = instance.content_type.get_object_for_this_type(id=instance.object_id)
        object_owner = None
        notification = None
        mentions = MentionsService.get_mentions(instance.text)
        url = None

        if model_class == Image:
            object_owner = obj.user
            notification = 'new_comment'
            url = settings.BASE_URL + instance.get_absolute_url()
        elif hasattr(model_class, 'edit_proposal_by'):
            object_owner = obj.edit_proposal_by
            notification = 'new_comment_to_edit_proposal'
            url = instance.get_absolute_url()
        elif model_class == Iotd:
            object_owner = obj.judge
            notification = 'new_comment_to_scheduled_iotd'
            url = AppRedirectionService.redirect(f'/iotd/judgement-queue#comments-{obj.pk}-{instance.pk}')

        if UserService(object_owner).shadow_bans(instance.author):
            log.info("Skipping notification for comment because %d shadow-bans %d" % (
                object_owner.pk, instance.author.pk))
            return

        exclude = MentionsService.get_mentioned_users_with_notification_enabled(mentions, 'new_comment_mention')

        if instance.parent and \
                instance.parent.author != instance.author and \
                not instance.pending_moderation:
            recipients = [x for x in [instance.parent.author] if x not in exclude]
            if recipients:
                push_notification(
                    recipients, instance.author, 'new_comment_reply',
                    {
                        'url': build_notification_url(url, instance.author),
                        'user': instance.author.userprofile.get_display_name(),
                        'user_url': settings.BASE_URL + reverse(
                            'user_page', kwargs={'username': instance.author.username}
                        ),
                    }
                )

        if model_class == Image:
            if (force or not instance.pending_moderation) and not obj.is_wip:
                add_story(instance.author,
                          verb='VERB_COMMENTED_IMAGE',
                          action_object=instance,
                          target=obj)

        if object_owner and notification:
            if instance.author != object_owner and \
                    (instance.parent is None or instance.parent.author != object_owner) and \
                    not instance.pending_moderation:
                recipients = [x for x in [object_owner] if x not in exclude]
                if recipients:
                    push_notification(
                        recipients, instance.author, notification,
                        {
                            'url': build_notification_url(url, instance.author),
                            'user': instance.author.userprofile.get_display_name(),
                            'user_url': settings.BASE_URL + reverse(
                                'user_page', kwargs={'username': instance.author.username}
                            ),
                        }
                    )
Пример #25
0
def send_edit_proposal_created_notification(sender, instance, created,
                                            **kwargs):
    if created and instance.edit_proposal_target.created_by:
        target = instance.edit_proposal_target
        owner = instance.edit_proposal_target.created_by
        user = instance.edit_proposal_by

        recipients = []

        if owner != user:
            recipients.append(owner)

        previous_proposals = User.objects.filter(
            **{
                f'astrobin_apps_equipment_{instance.__class__.__name__.lower()}_edit_proposals__'
                f'edit_proposal_target':
                target
            })
        previous_proposals_reviewed = User.objects.filter(
            **{
                f'astrobin_apps_equipment_{instance.__class__.__name__.lower()}_edit_proposals_reviewed__'
                f'edit_proposal_target':
                target
            })
        commenters = User.objects.filter(pk__in=NestedComment.objects.filter(
            content_type=ContentType.objects.get_for_model(instance.__class__),
            object_id__in=instance.__class__.objects.filter(
                edit_proposal_target=target)).values_list('author', flat=True))
        recipients.extend(list(previous_proposals))
        recipients.extend(list(previous_proposals_reviewed))
        recipients.extend(list(commenters))
        recipients = list(set(recipients))
        recipients.remove(user)

        if len(recipients) > 0:
            push_notification(
                recipients, user, 'equipment-edit-proposal-created', {
                    'user':
                    user.userprofile.get_display_name(),
                    'user_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse('user_page', args=(user.username, ))),
                    'item':
                    f'{target.brand.name if target.brand else _("(DIY)")} {target.name}',
                    'item_url':
                    build_notification_url(
                        AppRedirectionService.redirect(
                            f'/equipment'
                            f'/explorer'
                            f'/{target.item_type}/{target.pk}'
                            f'/{target.slug}')),
                    'edit_proposal_url':
                    build_notification_url(
                        AppRedirectionService.redirect(
                            f'/equipment'
                            f'/explorer'
                            f'/{target.item_type}/{target.pk}'
                            f'/{target.slug}'
                            f'/edit-proposals'
                            f'/{instance.pk}/')),
                })
Пример #26
0
def image_post_save(sender, instance, created, **kwargs):
    # type: (object, Image, bool, object) -> None

    if created:
        instance.user.userprofile.premium_counter += 1
        instance.user.userprofile.save(keep_deleted=True)

        if not instance.is_wip:
            if not instance.skip_notifications:
                push_notification_for_new_image.apply_async(args=(
                    instance.user.pk,
                    instance.pk,
                ))
            if instance.moderator_decision == 1:
                add_story(instance.user,
                          verb='VERB_UPLOADED_IMAGE',
                          action_object=instance)

        if Image.all_objects.filter(user=instance.user).count() == 1:
            push_notification(
                [instance.user], None, 'congratulations_for_your_first_image',
                {
                    'BASE_URL': settings.BASE_URL,
                    'PREMIUM_MAX_IMAGES_FREE':
                    settings.PREMIUM_MAX_IMAGES_FREE,
                    'url': reverse_url('image_detail',
                                       args=(instance.get_id(), ))
                })

        mentions = MentionsService.get_mentions(instance.description_bbcode)
    else:
        mentions = cache.get("image.%d.image_pre_save_mentions" % instance.pk,
                             [])

    for username in mentions:
        user = get_object_or_None(User, username=username)
        if not user:
            try:
                profile = get_object_or_None(UserProfile, real_name=username)
                if profile:
                    user = profile.user
            except MultipleObjectsReturned:
                user = None
        if user and user != instance.user:
            thumb = instance.thumbnail_raw('gallery', None, sync=True)
            push_notification(
                [user], instance.user, 'new_image_description_mention', {
                    'image':
                    instance,
                    'image_thumbnail':
                    thumb.url if thumb else None,
                    'url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.user),
                    'user':
                    instance.user.userprofile.get_display_name(),
                    'user_url':
                    settings.BASE_URL + reverse_url(
                        'user_page', kwargs={'username': instance.user}),
                })

    if not instance.uploader_in_progress:
        groups = instance.user.joined_group_set.filter(autosubmission=True)
        for group in groups:
            if instance.is_wip:
                group.images.remove(instance)
            else:
                group.images.add(instance)

        if instance.user.userprofile.updated < datetime.datetime.now(
        ) - datetime.timedelta(minutes=5):
            instance.user.save()
            try:
                instance.user.userprofile.save(keep_deleted=True)
            except UserProfile.DoesNotExist:
                pass

        UserService(instance.user).clear_gallery_image_list_cache()

        if instance.user.userprofile.auto_submit_to_iotd_tp_process:
            IotdService.submit_to_iotd_tp_process(instance.user, instance,
                                                  False)
Пример #27
0
def forum_post_post_save(sender, instance, created, **kwargs):
    def notify_subscribers():
        push_notification(
            list(instance.topic.subscribers.exclude(pk=instance.user.pk)),
            instance.user, 'new_forum_reply', {
                'user':
                instance.user.userprofile.get_display_name(),
                'user_url':
                settings.BASE_URL +
                reverse_url('user_page', kwargs={'username': instance.user}),
                'post_url':
                build_notification_url(
                    settings.BASE_URL + instance.get_absolute_url(),
                    instance.user),
                'topic_url':
                build_notification_url(
                    settings.BASE_URL + instance.topic.get_absolute_url(),
                    instance.user),
                'topic_name':
                instance.topic.name,
                'unsubscribe_url':
                build_notification_url(
                    settings.BASE_URL + reverse_url('pybb:delete_subscription',
                                                    args=[instance.topic.id]),
                    instance.user)
            })

    if created:
        mentions = MentionsService.get_mentions(instance.body)

        if hasattr(instance.topic.forum, 'group'):
            instance.topic.forum.group.save()  # trigger date_updated update

        if get_pybb_profile(instance.user).autosubscribe and \
                perms.may_subscribe_topic(instance.user, instance.topic):
            instance.topic.subscribers.add(instance.user)

        if not instance.on_moderation:
            notify_subscribers()
        else:
            NotificationsService.email_superusers(
                'New forum post needs moderation',
                '%s%s' % (settings.BASE_URL, instance.get_absolute_url()))

    else:
        mentions = cache.get(
            "user.%d.forum_post_pre_save_mentions" % instance.user.pk, [])

        if cache.get("user.%d.forum_post_pre_save_approved" %
                     instance.user.pk):
            notify_subscribers()

    for username in mentions:
        try:
            user = User.objects.get(username=username)
            push_notification(
                [user], instance.user, 'new_forum_post_mention', {
                    'url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.user),
                    'user':
                    instance.user.userprofile.get_display_name(),
                    'user_url':
                    settings.BASE_URL + reverse_url(
                        'user_page', kwargs={'username': instance.user}),
                    'post':
                    instance.topic.name,
                })
        except User.DoesNotExist:
            pass

    cache_key = make_template_fragment_key(
        'home_page_latest_from_forums',
        (instance.user.pk, instance.user.userprofile.language))
    cache.delete(cache_key)
Пример #28
0
def forum_post_post_save(sender, instance, created, **kwargs):
    def notify_subscribers(mentions):
        # type: (List[str]) -> None
        recipients = list(
            instance.topic.subscribers.exclude(pk__in=list(
                set([instance.user.pk] + [
                    x.pk for x in MentionsService.
                    get_mentioned_users_with_notification_enabled(
                        mentions, 'new_forum_post_mention')
                ]))))

        if recipients:
            push_notification(
                recipients, instance.user, 'new_forum_reply', {
                    'user':
                    instance.user.userprofile.get_display_name(),
                    'user_url':
                    settings.BASE_URL + reverse_url(
                        'user_page', kwargs={'username': instance.user}),
                    'post_url':
                    build_notification_url(
                        settings.BASE_URL + instance.get_absolute_url(),
                        instance.user),
                    'topic_url':
                    build_notification_url(
                        settings.BASE_URL + instance.topic.get_absolute_url(),
                        instance.user),
                    'topic_name':
                    instance.topic.name,
                    'unsubscribe_url':
                    build_notification_url(
                        settings.BASE_URL +
                        reverse_url('pybb:delete_subscription',
                                    args=[instance.topic.id]), instance.user)
                })

    def notify_mentioned(mentions):
        # type: (List[str]) -> None
        for username in mentions:
            user = get_object_or_None(User, username=username)
            if user is None:
                try:
                    profile = get_object_or_None(UserProfile,
                                                 real_name=username)
                    if profile:
                        user = profile.user
                except MultipleObjectsReturned:
                    user = None
            if user:
                push_notification(
                    [user], instance.user, 'new_forum_post_mention', {
                        'url':
                        build_notification_url(
                            settings.BASE_URL + instance.get_absolute_url(),
                            instance.user),
                        'user':
                        instance.user.userprofile.get_display_name(),
                        'user_url':
                        settings.BASE_URL + reverse_url(
                            'user_page', kwargs={'username': instance.user}),
                        'post':
                        instance.topic.name,
                    })

    if created:
        if hasattr(instance.topic.forum, 'group'):
            instance.topic.forum.group.save()  # trigger date_updated update

        if get_pybb_profile(instance.user).autosubscribe and \
                perms.may_subscribe_topic(instance.user, instance.topic):
            instance.topic.subscribers.add(instance.user)

        mentions = MentionsService.get_mentions(instance.body)
        if not instance.on_moderation:
            notify_subscribers(mentions)
            notify_mentioned(mentions)
        else:
            NotificationsService.email_superusers(
                'New forum post needs moderation',
                '%s%s' % (settings.BASE_URL, instance.get_absolute_url()))

    else:
        mentions = cache.get(
            "post.%d.forum_post_pre_save_mentions" % instance.pk, [])
        cache.delete("post.%d.forum_post_pre_save_mentions" % instance.pk)
        if cache.get("post.%d.forum_post_pre_save_approved" % instance.pk):
            push_notification(
                [instance.user], None, 'forum_post_approved', {
                    'url':
                    build_notification_url(settings.BASE_URL +
                                           instance.get_absolute_url())
                })
            notify_subscribers(mentions)
            notify_mentioned(mentions)
            cache.delete("post.%d.forum_post_pre_save_approved" % instance.pk)

    cache_key = make_template_fragment_key(
        'home_page_latest_from_forums',
        (instance.user.pk, instance.user.userprofile.language))
    cache.delete(cache_key)
Пример #29
0
def group_members_changed(sender, instance, **kwargs):
    action = kwargs['action']
    pk_set = kwargs['pk_set']

    group_sync_map = {
        'IOTD Submitters':
        ['iotd_submitters', 'content_moderators', 'iotd_staff'],
        'IOTD Reviewers':
        ['iotd_reviewers', 'content_moderators', 'iotd_staff'],
        'IOTD Judges': ['iotd_judges', 'content_moderators', 'iotd_staff'],
    }
    if instance.name in list(group_sync_map.keys()):
        for django_group in group_sync_map[instance.name]:
            DjangoGroup.objects.get_or_create(name=django_group)
        django_groups = DjangoGroup.objects.filter(
            name__in=group_sync_map[instance.name])
    try:
        iotd_staff_group = Group.objects.get(name='IOTD Staff')
    except Group.DoesNotExist:
        iotd_staff_group = None

    if action == 'post_add':
        users = [
            profile.user
            for profile in UserProfile.objects.filter(user__pk__in=pk_set)
        ]
        instance.save()  # trigger date_updated update

        if instance.public:
            for pk in pk_set:
                user = UserProfile.objects.get(user__pk=pk).user
                if user != instance.owner:
                    followers = [
                        x.user for x in ToggleProperty.objects.
                        toggleproperties_for_object("follow", user)
                    ]
                    push_notification(
                        followers + [instance.owner], user,
                        'user_joined_public_group', {
                            'user':
                            user.userprofile.get_display_name(),
                            'user_url':
                            build_notification_url(
                                settings.BASE_URL + reverse_url(
                                    'user_page',
                                    kwargs={'username': user.username}), user),
                            'group_name':
                            instance.name,
                            'url':
                            build_notification_url(
                                settings.BASE_URL + reverse_url(
                                    'group_detail', args=(instance.pk, )),
                                user),
                        })

                    add_story(user,
                              verb='VERB_JOINED_GROUP',
                              action_object=instance)

        if instance.autosubmission:
            images = Image.objects_including_wip.filter(user__pk__in=pk_set)
            for image in images:
                instance.images.add(image)

        # Sync IOTD AstroBin groups with django groups
        if instance.name in list(group_sync_map.keys()):
            for django_group in django_groups:
                django_group.user_set.add(*list(users))
            if iotd_staff_group:
                for user in users:
                    iotd_staff_group.members.add(user)

    elif action == 'post_remove':
        users = [
            profile.user
            for profile in UserProfile.objects.filter(user__pk__in=pk_set)
        ]
        images = Image.objects_including_wip.filter(user__pk__in=pk_set)
        for image in images:
            instance.images.remove(image)

        if instance.forum and not instance.public:
            topics = Topic.objects.filter(forum=instance.forum)
            for topic in topics:
                topic.subscribers.remove(*User.objects.filter(
                    pk__in=kwargs['pk_set']))

        # Sync IOTD AstroBin groups with django groups
        if instance.name in list(group_sync_map.keys()):
            all_members = []
            all_members_chain = chain([
                x.members.all()
                for x in Group.objects \
                    .filter(name__in=list(group_sync_map.keys())) \
                    .exclude(name=instance.name)
            ])
            for chain_item in all_members_chain:
                all_members += chain_item
            for user in [x for x in users if x not in all_members]:
                for django_group in django_groups:
                    django_group.user_set.remove(user)
                if iotd_staff_group:
                    iotd_staff_group.members.remove(user)

    elif action == 'pre_clear':
        # Sync IOTD AstroBin groups with django groups
        users = instance.members.all()
        if instance.name in list(group_sync_map.keys()):
            all_members = []
            all_members_chain = chain([
                x.members.all()
                for x in Group.objects \
                    .filter(name__in=list(group_sync_map.keys())) \
                    .exclude(name=instance.name)
            ])
            for chain_item in all_members_chain:
                all_members += chain_item
            for user in [x for x in users if x not in all_members]:
                for django_group in django_groups:
                    django_group.user_set.remove(user)
                if iotd_staff_group:
                    iotd_staff_group.members.remove(user)

    elif action == 'post_clear':
        instance.images.clear()
Пример #30
0
def toggleproperty_post_save(sender, instance, created, **kwargs):
    if hasattr(instance.content_object, "updated"):
        # This will trigger the auto_now fields in the content_object
        kwargs = {}
        if issubclass(type(instance.content_object), SafeDeleteModel):
            kwargs['keep_deleted'] = True
        instance.content_object.save(**kwargs)

    if created:
        verb = None

        if instance.property_type in ("like", "bookmark"):

            if instance.content_type == ContentType.objects.get_for_model(
                    Image):
                image = instance.content_type.get_object_for_this_type(
                    id=instance.object_id)
                Image.all_objects.filter(pk=instance.content_object.pk).update(
                    updated=timezone.now())

                if image.is_wip:
                    return

                if instance.property_type == "like":
                    verb = 'VERB_LIKED_IMAGE'
                elif instance.property_type == "bookmark":
                    verb = 'VERB_BOOKMARKED_IMAGE'
                else:
                    return

                push_notification(
                    [instance.content_object.user], instance.user,
                    'new_' + instance.property_type, {
                        'url':
                        build_notification_url(
                            settings.BASE_URL +
                            instance.content_object.get_absolute_url(),
                            instance.user),
                        'title':
                        instance.content_object.title,
                        'user':
                        instance.user.userprofile.get_display_name(),
                        'user_url':
                        settings.BASE_URL + reverse_url(
                            'user_page',
                            kwargs={'username': instance.user.username}),
                    })

            elif instance.content_type == ContentType.objects.get_for_model(
                    NestedComment):
                push_notification(
                    [instance.content_object.author], instance.user,
                    'new_comment_like', {
                        'url':
                        build_notification_url(
                            settings.BASE_URL +
                            instance.content_object.get_absolute_url(),
                            instance.user),
                        'user':
                        instance.user.userprofile.get_display_name(),
                        'user_url':
                        settings.BASE_URL + reverse_url(
                            'user_page',
                            kwargs={'username': instance.user.username}),
                        'comment':
                        instance.content_object.text
                    })

                UserProfile.all_objects.filter(
                    user=instance.content_object.author).update(
                        updated=timezone.now())

            elif instance.content_type == ContentType.objects.get_for_model(
                    Post):
                push_notification(
                    [instance.content_object.user], instance.user,
                    'new_forum_post_like', {
                        'url':
                        build_notification_url(
                            settings.BASE_URL +
                            instance.content_object.get_absolute_url(),
                            instance.user),
                        'user':
                        instance.user.userprofile.get_display_name(),
                        'user_url':
                        settings.BASE_URL + reverse_url(
                            'user_page',
                            kwargs={'username': instance.user.username}),
                        'post':
                        instance.content_object.topic.name
                    })

                UserProfile.all_objects.filter(
                    user=instance.content_object.user).update(
                        updated=timezone.now())

            if verb is not None:
                add_story(instance.user,
                          verb=verb,
                          action_object=instance.content_object)

        elif instance.property_type == "follow":
            user_ct = ContentType.objects.get_for_model(User)
            if instance.content_type == user_ct:
                followed_user = user_ct.get_object_for_this_type(
                    pk=instance.object_id)
                push_notification(
                    [followed_user], instance.user, 'new_follower', {
                        'object':
                        instance.user.userprofile.get_display_name(),
                        'object_url':
                        build_notification_url(
                            settings.BASE_URL + reverse_url(
                                'user_page',
                                kwargs={'username': instance.user.username}),
                            instance.user),
                    })