Esempio n. 1
0
    def send_rsc(self, request):
        recipient_id = request.data.get('recipient_id', '')
        amount = request.data.get('amount', 0)
        if recipient_id:
            user = request.user
            user_id = user.id
            content_type = ContentType.objects.get(model='distribution')
            proof_content_type = ContentType.objects.get(model='user')
            proof = {
                'table': 'user_user',
                'record': {
                    'id': user_id,
                    'email': user.email,
                    'name': user.first_name + ' ' + user.last_name
                }
            }
            distribution = Distribution('MOD_PAYOUT', amount, give_rep=False)
            timestamp = time.time()
            user_proof = User.objects.get(id=recipient_id)
            distributor = Distributor(distribution, user_proof, user_proof,
                                      timestamp)

            distributor.distribute()

        return Response({"message": 'RSC Sent!'})
Esempio n. 2
0
def distribute_for_censor(sender, instance, created, update_fields, **kwargs):
    timestamp = time()
    distributor = None
    hubs = None

    if check_censored(created, update_fields) is True:
        try:
            if isinstance(instance, BulletPoint):
                distribution = distributions.BulletPointCensored
                recipient = instance.bullet_point.created_by
                hubs = instance.bullet_point.paper.hubs

            elif check_is_discussion_item(instance):
                distribution = get_discussion_censored_distribution(instance)
                recipient = instance.created_by
                hubs = get_discussion_hubs(instance)

            else:
                raise TypeError

            all_hubs = None
            if hubs is not None:
                all_hubs = hubs.all()

            if is_eligible_user(recipient):
                distributor = Distributor(distribution, recipient, instance,
                                          timestamp, all_hubs)

        except TypeError as e:
            error = ReputationSignalError(e, "Failed to distribute")
            print(error)
            sentry.log_error(error)

    if distributor is not None:
        distributor.distribute()
Esempio n. 3
0
def distribute_for_create_summary(sender, instance, created, update_fields,
                                  **kwargs):
    timestamp = time()
    recipient = instance.proposed_by

    if is_eligible_for_create_summary(created, recipient):
        distribution = distributions.CreateSummary
    elif is_eligible_for_create_first_summary(created, update_fields,
                                              instance):
        distribution = distributions.CreateFirstSummary
    else:
        return

    last_distribution = recipient.reputation_records.filter(
        Q(distribution_type=distributions.CreateSummary)
        | Q(distribution_type=distributions.CreateFirstSummary)).last()
    if check_summary_distribution_interval(last_distribution):
        distributor = Distributor(
            distribution,
            recipient,
            instance,
            timestamp,
            instance.paper.hubs.all(),
        )
        record = distributor.distribute()
Esempio n. 4
0
 def deposit_rsc(self, request):
     """
     This is a request to deposit RSC from our researchhub-async-service
     TODO: Add a websocket call here so we can ping the frontend that the transaction completed
     """
     deposit = Deposit.objects.get(id=request.data.get("deposit_id"))
     amt = deposit.amount
     user = deposit.user
     distribution = Dist("DEPOSIT", amt, give_rep=False)
     distributor = Distributor(distribution, user, user, time.time())
     distributor.distribute()
     return Response({"message": "Deposit successful"})
Esempio n. 5
0
def distribute_rsc(request):
    data = request.data
    recipient_id = data.get("recipient_id")
    amount = data.get("amount")

    user = User.objects.get(id=recipient_id)
    distribution = Dist("REWARD", amount, give_rep=False)
    distributor = Distributor(distribution, user, user, time.time())
    distributor.distribute()

    response = Response({"data": f"Gave {amount} RSC to {user.email}"},
                        status=200)
    return response
Esempio n. 6
0
def distribute_for_bullet_point_vote(sender, instance, created, update_fields,
                                     **kwargs):
    timestamp = time()
    voter = instance.created_by
    recipient = instance.bulletpoint.created_by

    if created and is_eligible_for_bulletpoint_vote(recipient, voter):
        hubs = instance.bulletpoint.paper.hubs
        distribution = get_bulletpoint_vote_item_distribution(instance)

        distributor = Distributor(distribution, recipient, instance, timestamp,
                                  hubs.all())

        record = distributor.distribute()
Esempio n. 7
0
def distribute_for_censor_paper(sender, instance, using, **kwargs):
    timestamp = time()
    flags = instance.flags.select_related("created_by").all()
    for flag in flags:
        recipient = flag.created_by
        if is_eligible_user(recipient):
            distributor = Distributor(
                distributions.FlagPaper,
                recipient,
                instance,
                timestamp,
                instance.hubs.all(),
            )
            record = distributor.distribute()
Esempio n. 8
0
def distribute_for_create_bullet_point(sender, instance, created, **kwargs):
    timestamp = time()
    recipient = instance.created_by
    hubs = None
    if created and is_eligible_for_create_bullet_point(recipient):
        if isinstance(instance, BulletPoint) and check_key_takeaway_interval(
                instance, recipient):
            distribution = distributions.CreateBulletPoint
            hubs = instance.paper.hubs
        else:
            return

        distributor = Distributor(distribution, recipient, instance, timestamp,
                                  hubs.all())
        record = distributor.distribute()
Esempio n. 9
0
def distribute_for_paper_upvoted(sender, instance, created, update_fields,
                                 **kwargs):
    """Distributes reputation to the uploader."""
    timestamp = time()
    recipient = instance.paper.uploaded_by

    if is_eligible_for_paper_upvoted(created, instance.created_by, recipient):
        distributor = Distributor(
            distributions.create_upvote_distribution(
                distributions.PaperUpvoted.name, instance.paper, instance),
            recipient,
            instance,
            timestamp,
            instance.paper.hubs.all(),
        )
        record = distributor.distribute()
Esempio n. 10
0
    def distribute_referral_reward(self, user):
        timestamp = time()

        referrer = user.invited_by
        if not referrer:
            referrer = user

        distribution = Distributor(
            distributions.ReferralApproved,
            user,
            referrer,
            timestamp,
            None,
        )
        referred_distribution_record = distribution.distribute()

        if referrer:
            distribution = Distributor(
                distributions.ReferralApproved,
                referrer,
                referrer,
                timestamp,
                None,
            )
            distribution.distribute()

        return referred_distribution_record
Esempio n. 11
0
def create_upvote_distribution(vote_type, paper=None, vote=None):
    from user.utils import calculate_eligible_enhanced_upvotes

    eligible_enhanced_upvote = False
    if vote:
        eligible_enhanced_upvote = calculate_eligible_enhanced_upvotes(
            vote.created_by)

    if not eligible_enhanced_upvote:
        return Distribution(vote_type, 1, 1)

    distribution_amount = calculate_rsc_per_upvote()

    if paper:
        from reputation.distributor import Distributor
        from researchhub_case.models import AuthorClaimCase
        author_distribution_amount = distribution_amount * .75
        distribution_amount *= .25  # authors get 75% of the upvote score
        distributed_amount = 0
        author_count = paper.true_author_count()

        for author in paper.authors.all():
            if author.user and AuthorClaimCase.objects.filter(
                    target_paper=paper, requestor=author.user,
                    status=APPROVED).exists():
                timestamp = time()
                amt = author_distribution_amount / author_count
                distributor = Distributor(
                    Distribution(vote_type, amt),
                    author.user,
                    paper,
                    timestamp,
                    paper.hubs.all(),
                )
                record = distributor.distribute()
                distributed_amount += amt

        from reputation.models import AuthorRSC
        AuthorRSC.objects.create(
            paper=paper,
            amount=author_distribution_amount - distributed_amount,
        )

    return Distribution(vote_type, distribution_amount, 1)
def reward_author_claim_case(requestor_author, paper, claim_case):
    vote_reward = requestor_author.calculate_score()

    author_pot_query = AuthorRSC.objects.filter(paper=paper, )

    author_pot_amount = author_pot_query.aggregate(Sum('amount')).get(
        'amount__sum', 0) or 0

    author_count = paper.true_author_count()
    author_pot_amount /= author_count

    if author_pot_amount:
        distributor = Distributor(
            dist('UPVOTE_RSC_POT', author_pot_amount),
            requestor_author.user,
            requestor_author,
            time.time(),
        )
        record = distributor.distribute()
        claim_case.claimed_rsc.add(*author_pot_query)

    try:
        distributor = Distributor(dist('REWARD', vote_reward, False),
                                  requestor_author.user, requestor_author,
                                  time.time())
        distribution = distributor.distribute()
        return distribution
    except Exception as exception:
        print("reward_author_claim_case: ", exception)
        sentry.log_error(exception)
Esempio n. 13
0
    def test_no_doi_with_sufficient_funds(self):
        author = create_random_default_user('author')
        hub = create_hub()

        self.client.force_authenticate(author)

        distributor = Distributor(Distribution('TEST_REWARD', 5, False),
                                  author, None, time.time())
        distributor.distribute()

        doc_response = self.client.post(
            "/api/researchhub_posts/", {
                "assign_doi": False,
                "document_type": "DISCUSSION",
                "created_by": author.id,
                "full_src": "body",
                "is_public": True,
                "renderable_text": "body",
                "title": "title",
                "hubs": [hub.id],
            })

        self.assertEqual(doc_response.status_code, 200)
        self.assertEqual(int(author.get_balance()), 5)
Esempio n. 14
0
def distribute_for_discussion_vote(sender, instance, created, update_fields,
                                   **kwargs):
    """Distributes reputation to the creator of the item voted on."""
    timestamp = time()
    distributor = None
    try:
        recipient = instance.item.created_by
    except Exception as e:
        error = ReputationSignalError(e, "Invalid recipient")
        sentry.log_error(e)
        return

    voter = instance.created_by

    if (created or vote_type_updated(update_fields)
        ) and is_eligible_for_discussion_vote(recipient, voter):
        hubs = None
        item = instance.item
        if isinstance(item, Comment):
            if item.parent.paper is not None:
                hubs = item.parent.paper.hubs
            elif item.parent.post is not None:
                hubs = item.parent.post.unified_document.hubs
            elif item.parent.hypothesis is not None:
                hubs = item.parent.hypothesis.unified_document.hubs
        elif isinstance(item, Reply):
            try:
                if item.parent.parent.paper is not None:
                    hubs = item.parent.parent.paper.hubs
                elif item.parent.parent.post is not None:
                    hubs = item.parent.parent.post.unified_document.hubs
                elif item.parent.parent.hypothesis is not None:
                    hubs = item.parent.parent.hypothesis.unified_document.hubs
            except Exception as e:
                sentry.log_error(e)
        elif isinstance(item, Thread):
            if item.paper is not None:
                hubs = item.paper.hubs
            elif item.post is not None:
                hubs = item.post.unified_document.hubs
            elif item.hypothesis is not None:
                hubs = item.hypothesis.unified_document.hubs
        elif isinstance(item, ResearchhubPost):
            hubs = item.unified_document.hubs
        elif isinstance(item, Hypothesis):
            hubs = item.unified_document.hubs
        elif isinstance(item, Citation):
            hubs = item.source.hubs

        # TODO: This needs to be altered so that if the vote changes the
        # original distribution is deleted if not yet withdrawn

        if created:
            try:
                # NOTE: Only comment seems to be supporting distribution
                distribution = get_discussion_vote_item_distribution(instance)
                distributor = Distributor(distribution, recipient, instance,
                                          timestamp, hubs.all())
            except TypeError as e:
                error = ReputationSignalError(
                    e, "Failed to distribute for reaction vote")
                sentry.log_error(error)

    if distributor is not None and recipient != instance.created_by:
        record = distributor.distribute()
Esempio n. 15
0
def create_action(sender, instance, created, **kwargs):
    if created:
        if sender == Summary:
            user = instance.proposed_by
        elif sender == Paper or sender == PaperSubmission:
            user = instance.uploaded_by
        else:
            if sender == Thread:
                thread = instance
                if thread.is_removed:
                    content_id = f"{type(thread).__name__}_{thread.id}"
                    decisions_api.apply_bad_content_decision(
                        thread.created_by, content_id)
                    events_api.track_flag_content(
                        thread.created_by,
                        content_id,
                        1,
                    )
            user = instance.created_by
        """
        If we're creating an action for the first time,
        check if we've been referred
        """
        referral_content_types = [
            get_content_type_for_model(Thread),
            get_content_type_for_model(Reply),
            get_content_type_for_model(Comment),
            get_content_type_for_model(Paper),
            get_content_type_for_model(ResearchhubPost),
            get_content_type_for_model(Hypothesis),
        ]
        if (user is not None and user.invited_by and not Action.objects.filter(
                user=user, content_type__in=referral_content_types).exists()
                and sender in [
                    Thread, Reply, Comment, Paper, ResearchhubPost, Hypothesis
                ]):
            timestamp = time()

            if calculate_show_referral(user.invited_by):
                referred = Distributor(
                    distributions.Referral,
                    user,
                    user.invited_by,
                    timestamp,
                    None,
                )
                referred.distribute()

                referrer = Distributor(
                    distributions.Referral,
                    user.invited_by,
                    user.invited_by,
                    timestamp,
                    None,
                )
                referrer.distribute()

        vote_types = [PaperVote, ReactionVote, BulletPointVote, SummaryVote]
        display = (False if
                   (sender in vote_types or sender == PaperSubmission
                    or sender != ReactionVote and
                    (hasattr(instance, "is_removed") and instance.is_removed))
                   else True)

        action = Action.objects.create(item=instance,
                                       user=user,
                                       display=display)

        hubs = []
        if sender == Paper:
            hubs = instance.hubs.all()
        elif sender != BulletPointVote and sender != SummaryVote:
            hubs = get_related_hubs(instance)
        if hubs:
            action.hubs.add(*hubs)
        create_notification(sender, instance, created, action, **kwargs)

        return action
Esempio n. 16
0
    def create(self, request):
        user = request.user
        data = request.data

        amount = data['amount']
        purchase_method = data['purchase_method']
        purchase_type = data['purchase_type']
        content_type_str = data['content_type']
        object_id = data['object_id']
        transfer_rsc = False
        recipient = None

        if content_type_str not in self.ALLOWED_CONTENT_TYPES:
            return Response(status=400)

        if purchase_method not in (Purchase.OFF_CHAIN, Purchase.ON_CHAIN):
            return Response(status=400)

        decimal_amount = decimal.Decimal(amount)
        if decimal_amount <= 0:
            return Response(status=400)

        content_type = ContentType.objects.get(model=content_type_str)
        with transaction.atomic():
            if purchase_method == Purchase.ON_CHAIN:
                purchase = Purchase.objects.create(
                    user=user,
                    content_type=content_type,
                    object_id=object_id,
                    purchase_method=purchase_method,
                    purchase_type=purchase_type,
                    amount=amount)
            else:
                user_balance = user.get_balance()
                if user_balance - decimal_amount < 0:
                    return Response('Insufficient Funds', status=402)

                purchase = Purchase.objects.create(
                    user=user,
                    content_type=content_type,
                    object_id=object_id,
                    purchase_method=purchase_method,
                    purchase_type=purchase_type,
                    amount=amount,
                    paid_status=Purchase.PAID)

                source_type = ContentType.objects.get_for_model(purchase)
                Balance.objects.create(
                    user=user,
                    content_type=source_type,
                    object_id=purchase.id,
                    amount=f'-{amount}',
                )

            purchase_hash = purchase.hash()
            purchase.purchase_hash = purchase_hash
            purchase_boost_time = purchase.get_boost_time(amount)
            purchase.boost_time = purchase_boost_time
            purchase.group = purchase.get_aggregate_group()
            purchase.save()

            item = purchase.item
            context = {
                'purchase_minimal_serialization': True,
                'exclude_stats': True
            }

            #  transfer_rsc is set each time just in case we want
            #  to disable rsc transfer for a specific item
            if content_type_str == 'paper':
                paper = Paper.objects.get(id=object_id)
                unified_doc = paper.unified_document
                paper.calculate_hot_score()
                recipient = paper.uploaded_by
                cache_key = get_cache_key('paper', object_id)
                cache.delete(cache_key)
                transfer_rsc = True

                hub_ids = paper.hubs.values_list('id', flat=True)
                reset_unified_document_cache(
                    hub_ids,
                    document_type=['all', 'paper'],
                    filters=[TRENDING],
                )
            elif content_type_str == 'thread':
                transfer_rsc = True
                recipient = item.created_by
                unified_doc = item.unified_document
            elif content_type_str == 'comment':
                transfer_rsc = True
                unified_doc = item.unified_document
                recipient = item.created_by
            elif content_type_str == 'reply':
                transfer_rsc = True
                unified_doc = item.unified_document
                recipient = item.created_by
            elif content_type_str == 'summary':
                transfer_rsc = True
                recipient = item.proposed_by
                unified_doc = item.paper.unified_document
            elif content_type_str == 'bulletpoint':
                transfer_rsc = True
                recipient = item.created_by
                unified_doc = item.paper.unified_document
            elif content_type_str == 'researchhubpost':
                transfer_rsc = True
                recipient = item.created_by
                unified_doc = item.unified_document

                hub_ids = unified_doc.hubs.values_list('id', flat=True)
                reset_unified_document_cache(
                    hub_ids,
                    document_type=['all', 'posts'],
                    filters=[TRENDING],
                )

            if unified_doc.is_removed:
                return Response('Content is removed', status=403)

            if transfer_rsc and recipient and recipient != user:
                distribution = create_purchase_distribution(amount)
                distributor = Distributor(distribution, recipient, purchase,
                                          time.time())
                distributor.distribute()

        serializer = self.serializer_class(purchase, context=context)
        serializer_data = serializer.data

        if recipient and user:
            self.send_purchase_notification(purchase, unified_doc, recipient)
            self.send_purchase_email(purchase, recipient, unified_doc)

        create_contribution.apply_async((Contribution.SUPPORTER, {
            'app_label': 'purchase',
            'model': 'purchase'
        }, user.id, unified_doc.id, purchase.id),
                                        priority=2,
                                        countdown=10)
        return Response(serializer_data, status=201)
Esempio n. 17
0
def editor_daily_payout_task():
    from reputation.distributor import Distributor
    User = apps.get_model('user.User')
    today = datetime.date.today()
    num_days_this_month = monthrange(today.year, today.month)[1]
    result = get_daily_rsc_payout_amount_from_deep_index(num_days_this_month)

    # Keeping record of exchange rate used today
    RscExchangeRate.objects.create(
      rate=result['rate'],
      target_currency=USD,
    )

    excluded_user_email = Gatekeeper.objects.filter(
        type__in=[EDITOR_PAYOUT_ADMIN, PAYOUT_EXCLUSION_LIST]
    ).values_list('email', flat=True)

    editors = User.objects.filter(
        permissions__isnull=False,
        permissions__access_type=EDITOR,
        permissions__content_type=ContentType.objects.get_for_model(Hub)
    ).distinct().exclude(email__in=(excluded_user_email))

    csv_prep = {
      'amount-rsc': [],
      'emails': [],
      'names': [],
      'usd-rsc-rate': [],
    }

    for editor in editors.iterator():
        try:
            pay_amount = result['pay_amount']
            distributor = Distributor(
                  # this is NOT the model. It's a simple object
                  Distribution('EDITOR_PAYOUT', pay_amount, False),
                  editor,
                  None,
                  today
              )
            distributor.distribute()

            csv_prep['names'].append(
                editor.first_name or "" + editor.last_name or ""
            )
            csv_prep['emails'].append(editor.email)
            csv_prep['amount-rsc'].append(pay_amount)

        except Exception as error:
            sentry.log_error(error)
            print('error: ', error)
            pass

    try:
        title = f'Editor Payout {today}'
        csv_file = StringIO()
        csv_writer = csv.DictWriter(
          csv_file,
          # logical ordering
          fieldnames=['names', 'emails', 'amount-rsc', 'usd-rsc-rate']
        )
        csv_writer.writeheader()

        prepped_rows = []
        editor_count = editors.count()
        for index in range(editor_count):
            prepped_rows.append({
                'names': csv_prep['names'][index],
                'emails': csv_prep['emails'][index],
                'amount-rsc': csv_prep['amount-rsc'][index],
                'usd-rsc-rate': result['rate'],
            })

        csv_writer.writerows(prepped_rows)
        
        payout_admin_emails = Gatekeeper.objects.filter(
            type__in=[EDITOR_PAYOUT_ADMIN]
        ).values_list('email', flat=True)

        email_tag = '' if APP_ENV == 'production' else "[Staging - TEST] "
        email = EmailMessage(
            subject=f'{email_tag}{title}',
            body=f'{email_tag}Editor payout csv - {today}',
            from_email=f'{email_tag}ResearchHub <*****@*****.**>',
            to=payout_admin_emails,
        )
        email.attach(f'{title}.csv', csv_file.getvalue(), 'text/csv')
        email.send()
        return f"""{APP_ENV}: Users - {editor_count}. Rate - {result['rate']}. RSC - {pay_amount}"""

    except Exception as error:
        sentry.log_error(error)
        print('error: ', error)
        pass