Exemple #1
0
    def _create_summary(self, request):
        # TODO: Should we fail if they don't provide the previous summary?
        # Or just grab the last paper summary created and set it to previous?
        user = request.user
        summary = request.data.get('summary')
        paper_id = request.data.get('paper')
        summary_plain_text = request.data.get('summary_plain_text', '')
        previous_summary_id = request.data.get('previousSummaryId', None)

        created_location = None
        if request.query_params.get('created_location') == 'progress':
            created_location = Summary.CREATED_LOCATION_PROGRESS

        previous_summary = None
        if previous_summary_id is not None:
            previous_summary = Summary.objects.get(id=previous_summary_id)

        new_summary = Summary.objects.create(
            summary=summary,
            summary_plain_text=summary_plain_text,
            proposed_by=user,
            paper_id=paper_id,
            previous=previous_summary,
            created_location=created_location)

        tracked_summary = events_api.track_content_summary(
            user, new_summary, request, update=bool(previous_summary))
        update_user_risk_score(user, tracked_summary)

        return new_summary
Exemple #2
0
 def sift_track_update_content_comment(
     self, request, response, model, is_thread=False
 ):
     item = model.objects.get(pk=response.data["id"])
     tracked_comment = events_api.track_content_comment(
         item.created_by, item, request, is_thread=is_thread, update=True
     )
     update_user_risk_score(item.created_by, tracked_comment)
    def save_user(self, request, sociallogin, form=None):  # Saves new user
        if sociallogin.account.provider == OrcidProvider.id:
            sociallogin.user.username = self._generate_temporary_username(
                sociallogin)
            saved_user = super().save_user(request, sociallogin, form)
            self._merge_or_update_orcid_author(saved_user, sociallogin)
        else:
            saved_user = super().save_user(request, sociallogin, form)

        tracked_account = events_api.track_account(saved_user, request)
        update_user_risk_score(saved_user, tracked_account)
        return saved_user
Exemple #4
0
    def create(self, request, *args, **kwargs):
        # Do not allow user to manually set created_by
        try:
            del request.data['created_by']
        except KeyError:
            pass

        paper = request.data.get('paper', None)
        if paper is None:
            paper = get_document_id_from_path(request)
            if paper is None:
                return Response('Missing required field `paper`', status=400)
            request.data['paper'] = paper

        context = self.get_serializer_context()
        response = super().create(request, *args, **kwargs)
        bullet_id = response.data['id']

        bullet_point = BulletPoint.objects.get(pk=response.data['id'])
        update_or_create_vote(request, request.user, bullet_point, Vote.UPVOTE)
        response.data = BulletPointSerializer(
            bullet_point,
            context=context
        ).data

        tracked_bullet_point = events_api.track_content_bullet_point(
            bullet_point.created_by,
            bullet_point,
            request,
        )
        update_user_risk_score(bullet_point.created_by, tracked_bullet_point)

        # Deprecating bulletpoint contributions until(?)
        # we bring bulletpoints back

        # create_contribution.apply_async(
        #     (
        #         Contribution.CURATOR,
        #         {'app_label': 'bullet_point', 'model': 'bulletpoint'},
        #         request.user.id,
        #         paper,
        #         bullet_id
        #     ),
        #     priority=2,
        #     countdown=10
        # )
        return response
Exemple #5
0
    def edit(self, request, pk=None):
        bullet_point = self.get_object()
        user = request.user
        paper_id = request.data.get('paper', None)
        if paper_id is None:
            paper_id = get_document_id_from_path(request)
            if paper_id is None:
                return Response(
                    'Missing required field `paper`',
                    status=status.HTTP_400_BAD_REQUEST
                )
        text = request.data.get('text')
        plain_text = request.data.get('plain_text')

        tail = bullet_point.tail
        if tail is None:
            tail = bullet_point

        with transaction.atomic():
            head_bullet_point = BulletPoint.objects.create(
                bullet_type=bullet_point.bullet_type,
                paper_id=paper_id,
                tail=tail,
                previous=bullet_point,
                created_by=user,
                text=text,
                plain_text=plain_text,
                ordinal=bullet_point.ordinal,
                ordinal_is_locked=bullet_point.ordinal_is_locked,
                is_head=True,
                is_tail=False
            )
            bullet_point.remove_from_head()
            bullet_point.save()

            tracked_bullet_point = events_api.track_content_bullet_point(
                head_bullet_point.created_by,
                head_bullet_point,
                request,
                update=True
            )
            update_user_risk_score(head_bullet_point.created_by, tracked_bullet_point)

        serialized = self.get_serializer(instance=head_bullet_point)
        return Response(serialized.data, status=status.HTTP_201_CREATED)
    def update(self, instance, validated_data):
        request = self.context.get("request", None)
        authors = validated_data.pop("authors", [None])
        hubs = validated_data.pop("hubs", [None])
        raw_authors = validated_data.pop("raw_authors", [])
        file = validated_data.get("file", None)

        try:
            with transaction.atomic():

                # Temporary fix for updating read only fields
                # Not including file, pdf_url, and url because
                # those fields are processed
                read_only_fields = (self.Meta.read_only_fields +
                                    self.Meta.patch_read_only_fields)
                for read_only_field in read_only_fields:
                    if read_only_field in validated_data:
                        validated_data.pop(read_only_field, None)

                self._add_url(file, validated_data)
                self._clean_abstract(validated_data)

                paper = super(PaperSerializer,
                              self).update(instance, validated_data)
                paper.full_clean(exclude=["paper_type"])

                unified_doc = paper.unified_document
                paper_title = paper.paper_title or ""
                file = paper.file
                self._check_pdf_title(paper, paper_title, file)

                new_hubs = []
                remove_hubs = []
                if hubs:
                    current_hubs = paper.hubs.all()
                    for current_hub in current_hubs:
                        if current_hub not in hubs:
                            remove_hubs.append(current_hub)
                    for hub in hubs:
                        if hub not in current_hubs:
                            new_hubs.append(hub)
                    paper.hubs.remove(*remove_hubs)
                    paper.hubs.add(*hubs)
                    unified_doc.hubs.remove(*remove_hubs)
                    unified_doc.hubs.add(*hubs)
                    for hub in remove_hubs:
                        hub.paper_count = hub.get_paper_count()
                        hub.save(update_fields=["paper_count"])
                    for hub in new_hubs:
                        hub.paper_count = hub.get_paper_count()
                        hub.save(update_fields=["paper_count"])

                if authors:
                    current_authors = paper.authors.all()
                    remove_authors = []
                    for author in current_authors:
                        if author not in authors:
                            remove_authors.append(author)

                    new_authors = []
                    for author in authors:
                        if author not in current_authors:
                            new_authors.append(author)
                    paper.authors.remove(*remove_authors)
                    paper.authors.add(*new_authors)

                paper.set_paper_completeness()

                if file:
                    self._add_file(paper, file)

                updated_hub_ids = list(
                    map(lambda hub: hub.id, remove_hubs + new_hubs))
                if len(updated_hub_ids) > 0:
                    reset_unified_document_cache(
                        hub_ids=updated_hub_ids,
                        document_type=["paper", "all"],
                        filters=[NEWEST, TOP, TRENDING, DISCUSSED],
                        with_default_hub=True,
                    )

                if request:
                    tracked_paper = events_api.track_content_paper(
                        request.user, paper, request, update=True)
                    update_user_risk_score(request.user, tracked_paper)
                return paper
        except Exception as e:
            error = PaperSerializerError(e, "Failed to update paper")
            sentry.log_error(e, base_error=error.trigger)
            raise error
    def create(self, validated_data):
        request = self.context.get("request", None)
        if request:
            user = request.user
        else:
            user = None
        validated_data["uploaded_by"] = user

        if "url" in validated_data or "pdf_url" in validated_data:
            error = Exception("URL uploading is deprecated")
            sentry.log_error(error)
            raise error

        # Prepare validated_data by removing m2m
        authors = validated_data.pop("authors")
        hubs = validated_data.pop("hubs")
        hypothesis_id = validated_data.pop("hypothesis_id", None)
        citation_type = validated_data.pop("citation_type", None)
        file = validated_data.get("file")
        try:
            with transaction.atomic():
                # Temporary fix for updating read only fields
                # Not including file, pdf_url, and url because
                # those fields are processed
                for read_only_field in self.Meta.read_only_fields:
                    if read_only_field in validated_data:
                        validated_data.pop(read_only_field, None)

                # valid_doi = self._check_valid_doi(validated_data)
                # if not valid_doi:
                #     raise IntegrityError('DETAIL: Invalid DOI')

                self._add_url(file, validated_data)
                self._clean_abstract(validated_data)
                self._add_raw_authors(validated_data)

                paper = None

                if paper is None:
                    # It is important to note that paper signals
                    # are ran after call to super
                    paper = super(PaperSerializer, self).create(validated_data)
                    paper.full_clean(exclude=["paper_type"])

                unified_doc = paper.unified_document
                unified_doc_id = paper.unified_document.id
                if hypothesis_id:
                    self._add_citation(user, hypothesis_id, unified_doc,
                                       citation_type)

                paper_id = paper.id
                paper_title = paper.paper_title or ""
                file = paper.file
                self._check_pdf_title(paper, paper_title, file)
                # NOTE: calvinhlee - This is an antipattern. Look into changing
                Vote.objects.create(paper=paper,
                                    created_by=user,
                                    vote_type=Vote.UPVOTE)

                # Now add m2m values properly
                if validated_data["paper_type"] == Paper.PRE_REGISTRATION:
                    paper.authors.add(user.author_profile)

                # TODO: Do we still need add authors from the request content?
                paper.authors.add(*authors)

                self._add_orcid_authors(paper)
                paper.hubs.add(*hubs)
                for hub in hubs:
                    hub.paper_count = hub.get_paper_count()
                    hub.save(update_fields=["paper_count"])

                try:
                    self._add_file(paper, file)
                except Exception as e:
                    sentry.log_error(e, )

                paper.set_paper_completeness()
                # Fix adding references
                # self._add_references(paper)

                paper.pdf_license = paper.get_license(save=False)

                update_unified_document_to_paper(paper)

                tracked_paper = events_api.track_content_paper(
                    user, paper, request)
                update_user_risk_score(user, tracked_paper)

                create_contribution.apply_async(
                    (
                        Contribution.SUBMITTER,
                        {
                            "app_label": "paper",
                            "model": "paper"
                        },
                        user.id,
                        unified_doc_id,
                        paper_id,
                    ),
                    priority=3,
                    countdown=10,
                )

                celery_calculate_paper_twitter_score.apply_async((paper_id, ),
                                                                 priority=5,
                                                                 countdown=10)

                hub_ids = unified_doc.hubs.values_list("id", flat=True)
                if hub_ids.exists():
                    reset_unified_document_cache(
                        hub_ids,
                        document_type=["paper", "all"],
                        filters=[NEWEST],
                        with_default_hub=True,
                    )

                return paper
        except IntegrityError as e:
            sentry.log_error(e)
            raise e
        except Exception as e:
            error = PaperSerializerError(e, "Failed to create paper")
            sentry.log_error(error, base_error=error.trigger)
            raise error
Exemple #8
0
    def validate(self, attrs, retry=0):
        view = self.context.get('view')
        request = self._get_request()

        if not view:
            error = serializers.ValidationError(
                _("View is not defined, pass it as a context variable"))
            sentry.log_error(error)
            raise error

        adapter_class = getattr(view, 'adapter_class', None)
        if not adapter_class:
            error = serializers.ValidationError(
                _("Define adapter_class in view"))
            sentry.log_error(error)
            raise error

        adapter = adapter_class(request)
        app = adapter.get_provider().get_app(request)

        # More info on code vs access_token
        # http://stackoverflow.com/questions/8666316/facebook-oauth-2-0-code-and-token

        credential = attrs.get('credential')

        # Case 1: We received the access_token
        if attrs.get('access_token') or credential:
            access_token = attrs.get('access_token')
            if credential:
                access_token = credential

        # Case 2: We received the authorization code
        elif attrs.get('code'):
            self.callback_url = getattr(view, 'callback_url', None)
            self.client_class = getattr(view, 'client_class', None)

            if not self.callback_url:
                error = serializers.ValidationError(
                    _("Define callback_url in view"))
                sentry.log_error(error)
                raise error
            if not self.client_class:
                error = serializers.ValidationError(
                    _("Define client_class in view"))
                sentry.log_error(error)
                raise error

            code = attrs.get('code')

            provider = adapter.get_provider()
            scope = provider.get_scope(request)
            client = self.client_class(
                request,
                app.client_id,
                app.secret,
                adapter.access_token_method,
                adapter.access_token_url,
                'postmessage',  # This is the callback url
                scope)
            token = client.get_access_token(code)
            access_token = token['access_token']

        else:
            error = serializers.ValidationError(
                _("Incorrect input. access_token or code is required."))
            sentry.log_error(error)
            raise serializers.ValidationError(
                _("Incorrect input. access_token or code is required."))

        social_token = adapter.parse_token({'access_token': access_token})
        social_token.app = app

        login = None
        try:
            login = self.get_social_login(adapter, app, social_token,
                                          access_token)
            complete_social_login(request, login)
        except ConnectionTimeout:
            pass
        except NoReverseMatch as e:
            if 'account_inactive' in str(e):
                login_user = login.account.user
                tracked_login = events_api.track_login(login_user, '$failure',
                                                       request)
                update_user_risk_score(login_user, tracked_login)
                raise LoginError(None, 'Account is suspended')
        except Exception as e:
            error = LoginError(e, 'Login failed')
            sentry.log_info(error, error=e)
            if login:
                deleted = self._delete_user_account(login.user, error=e)
                if deleted and retry < 3:
                    return self.validate(attrs, retry=retry + 1)
            sentry.log_error(error, base_error=e)
            raise serializers.ValidationError(_("Incorrect value"))

        if login and not login.is_existing:
            # We have an account already signed up in a different flow
            # with the same email address: raise an exception.
            # This needs to be handled in the frontend. We can not just
            # link up the accounts due to security constraints
            if app_settings.UNIQUE_EMAIL:
                # Do we have an account already with this email address?
                account_exists = get_user_model().objects.filter(
                    email=login.user.email, ).exists()
                if account_exists:
                    sentry.log_info('User already registered with this e-mail')
                    deleted = self._delete_user_account(login.user)
                    if deleted and retry < 3:
                        return self.validate(attrs, retry=retry + 1)
                    raise serializers.ValidationError(
                        _("User already registered with this e-mail address."))

            login.lookup()
            login.save(request, connect=True)

        login_user = login.account.user
        attrs['user'] = login_user
        tracked_login = events_api.track_login(login_user, '$success', request)
        update_user_risk_score(login_user, tracked_login)

        try:
            visits = WebsiteVisits.objects.get(uuid=attrs['uuid'])
            visits.user = attrs['user']
            visits.save()
        except Exception as e:
            print(e)
            pass

        try:
            referral_code = attrs.get('referral_code')
            if referral_code:
                referral_user = User.objects.get(referral_code=referral_code)
                user = attrs['user']
                if referral_code and not user.invited_by and referral_user.id != user.id:
                    user.invited_by = referral_user
                    user.save()
        except Exception as e:
            print(e)
            sentry.log_error(e)
            pass

        request = self._get_request()
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')

        user = attrs['user']
        check_user_risk(user)

        if user.is_authenticated and not user.probable_spammer:
            try:
                country = geo.country(ip)
                user.country_code = country.get('country_code')
                user.save()
            except Exception as e:
                print(e)
                sentry.log_error(e)

        return attrs