Exemple #1
0
 def test_addr_to_token_valid(self):
     """Test the dashboard token lookup utility with a valid token."""
     token = addr_to_token('0x0000000000000000000000000000000000000000')
     assert isinstance(token, dict)
     assert token['addr'] == '0x0000000000000000000000000000000000000000'
     assert token['name'] == 'ETH'
     assert token['decimals'] == 18
Exemple #2
0
 def amount_per_period_to_gitcoin(self):
     from dashboard.tokens import addr_to_token
     token = addr_to_token(self.token_address, self.network)
     try:
         decimals = token.get('decimals', 0)
         return (float(self.gas_price) / 10**decimals)
     except:
         return 0
Exemple #3
0
    def amount_per_period_to_gitcoin(self):
        from dashboard.tokens import addr_to_token
        token = addr_to_token(self.token_address, self.network)

        # gas prices no longer take this amount times 10**18 decimals
        if self.created_on > timezone.datetime(2020, 6, 16, 15,
                                               0).replace(tzinfo=pytz.utc):
            return self.gas_price

        try:
            decimals = token.get('decimals', 0)
            return (float(self.gas_price) / 10**decimals)
        except:
            return 0
Exemple #4
0
    def get_subscription_hash_arguments(self):
        """Get the grant subscription hash from web3.

        Attributes:
            from (str): Subscription.contributor_address
            to (str): Grant.admin_address
            tokenAddress (str): Subscription.token_address
            tokenAmount (float): Subscription.amount_per_period
            periodSeconds (int): real_period_seconds in the Subscription model
            gasPrice (float): Subscription.gas_price
            nonce (int): The nonce is stored in the Contribution model. its created / managed by sync_geth
            signature (str): Subscription.contributor_signature

        Returns:
            str: The Subscription hash.

        """
        from dashboard.tokens import addr_to_token

        subs = self
        grant = subs.grant

        _from = subs.contributor_address
        to = grant.admin_address
        if grant.token_address != '0x0000000000000000000000000000000000000000':
            tokenAddress = grant.token_address
        else:
            tokenAddress = subs.token_address

        tokenAmount = subs.amount_per_period
        periodSeconds = subs.real_period_seconds
        gasPrice = subs.gas_price
        nonce = subs.get_nonce(_from)
        signature = subs.contributor_signature

        # TODO - figure out the number of decimals
        token = addr_to_token(tokenAddress, subs.grant.network)
        decimals = token.get('decimals', 0)

        return {
            'from': Web3.toChecksumAddress(_from),
            'to': Web3.toChecksumAddress(to),
            'tokenAddress': Web3.toChecksumAddress(tokenAddress),
            'tokenAmount': int(tokenAmount * 10**decimals),
            'periodSeconds': int(periodSeconds),
            'gasPrice': int(gasPrice),
            'nonce': int(nonce),
            'signature': signature,
        }
Exemple #5
0
    def get_debug_info(self):
        """Return grants contract."""
        from dashboard.utils import get_web3
        from dashboard.abi import erc20_abi
        from dashboard.tokens import addr_to_token
        try:
            web3 = get_web3(self.network)
            if not self.token_address:
                return "This subscription has no token_address"
            token_contract = web3.eth.contract(Web3.toChecksumAddress(
                self.token_address),
                                               abi=erc20_abi)
            balance = token_contract.functions.balanceOf(
                Web3.toChecksumAddress(self.contributor_address)).call()
            allowance = token_contract.functions.allowance(
                Web3.toChecksumAddress(self.contributor_address),
                Web3.toChecksumAddress(self.grant.contract_address)).call()
            gasPrice = self.gas_price
            is_active = self.get_is_active_from_web3()
            token = addr_to_token(self.token_address, self.network)
            next_valid_timestamp = self.get_next_valid_timestamp()
            decimals = token.get('decimals', 0)
            balance = balance / 10**decimals
            allowance = allowance / 10**decimals
            error_reason = "unknown"
            if not is_active:
                error_reason = 'not_active'
            if timezone.now().timestamp() < next_valid_timestamp:
                error_reason = 'before_next_valid_timestamp'
            if (float(balance) + float(gasPrice)) < float(
                    self.amount_per_period):
                error_reason = "insufficient_balance"
            if allowance < self.amount_per_period:
                error_reason = "insufficient_allowance"

            debug_info = f"""
error_reason: {error_reason}
==============================
is_active: {is_active}
decimals: {decimals}
balance: {balance}
allowance: {allowance}
amount_per_period: {self.amount_per_period}
next_valid_timestamp: {next_valid_timestamp}
"""
        except Exception as e:
            return str(e)
        return debug_info
Exemple #6
0
    def get_subscription_hash_arguments(self):
        """Returns the grants subscription hash (has to get it from web3)."""
        """
            from = Subscription.contributor_address,
            to = Grant.admin_address,
            tokenAddress = Subscription.token_address,
            tokenAmount = Subscription.amount_per_period,
            periodSeconds = real_period_seconds in the Subscription model
            gasPrice = Subscription.gas_price,
            nonce = The nonce is stored in the Contribution model. its created / managed by sync_geth
            signature = Subscription.contributor_signature
        """
        from dashboard.tokens import addr_to_token

        subs = self
        grant = subs.grant

        _from = subs.contributor_address
        to = grant.admin_address
        tokenAddress = subs.token_address
        tokenAmount = subs.amount_per_period
        periodSeconds = subs.real_period_seconds
        gasPrice = subs.gas_price
        nonce = subs.get_nonce(_from)
        signature = subs.contributor_signature

        #TODO - figure out the number of decimals
        token = addr_to_token(subs.token_address, subs.grant.network)
        decimals = token.get('decimals', 0)

        return {
            'from': Web3.toChecksumAddress(_from),
            'to': Web3.toChecksumAddress(to),
            'tokenAddress': Web3.toChecksumAddress(tokenAddress),
            'tokenAmount': int(tokenAmount  * 10**decimals),
            'periodSeconds': int(periodSeconds),
            'gasPrice': int(gasPrice * 10**9),
            'nonce': int(nonce),
            'signature': signature,
        }
Exemple #7
0
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id):
    """Handle new Bounty creation in the event of bounty changes.

    Possible Bounty Stages:
        0: Draft
        1: Active
        2: Dead

    Returns:
        dashboard.models.Bounty: The new Bounty object.

    """
    bounty_issuer = bounty_payload.get('issuer', {})
    metadata = bounty_payload.get('metadata', {})
    # fulfillments metadata will be empty when bounty is first created
    fulfillments = bounty_details.get('fulfillments', {})
    interested_comment_id = None
    submissions_comment_id = None
    interested_comment_id = None

    # start to process out all the bounty data
    url = bounty_payload.get('webReferenceURL')
    if url:
        url = normalize_url(url)
    else:
        raise UnsupportedSchemaException(
            'No webReferenceURL found. Cannot continue!')

    # Check if we have any fulfillments.  If so, check if they are accepted.
    # If there are no fulfillments, accepted is automatically False.
    # Currently we are only considering the latest fulfillment.  Std bounties supports multiple.
    # If any of the fulfillments have been accepted, the bounty is now accepted and complete.
    accepted = any(
        [fulfillment.get('accepted') for fulfillment in fulfillments])

    with transaction.atomic():
        old_bounties = old_bounties.distinct().order_by('created_on')
        latest_old_bounty = None
        token_address = bounty_payload.get(
            'tokenAddress', '0x0000000000000000000000000000000000000000')
        token_name = bounty_payload.get('tokenName', '')
        if not token_name:
            token = addr_to_token(token_address)
            if token:
                token_name = token['name']

        for old_bounty in old_bounties:
            if old_bounty.current_bounty:
                submissions_comment_id = old_bounty.submissions_comment
                interested_comment_id = old_bounty.interested_comment
            old_bounty.current_bounty = False
            old_bounty.save()
            latest_old_bounty = old_bounty

        bounty_kwargs = {
            'is_open':
            True if (bounty_details.get('bountyStage') == 1 and not accepted)
            else False,
            'raw_data':
            bounty_details,
            'metadata':
            metadata,
            'current_bounty':
            True,
            'accepted':
            accepted,
            'interested_comment':
            interested_comment_id,
            'submissions_comment':
            submissions_comment_id,
            'standard_bounties_id':
            bounty_id,
            'num_fulfillments':
            len(fulfillments),
            'value_in_token':
            bounty_details.get('fulfillmentAmount', Decimal(1.0))
        }
        if not latest_old_bounty:
            schemes = bounty_payload.get('schemes', {})
            bounty_kwargs.update({
                # info to xfr over from latest_old_bounty as override fields (this is because sometimes
                # ppl dont login when they first submit issue and it needs to be overridden)
                'web3_created':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_payload.get('created')),
                                    timezone=UTC),
                'github_url':
                url,
                'token_name':
                token_name,
                'token_address':
                token_address,
                'privacy_preferences':
                bounty_payload.get('privacy_preferences', {}),
                'expires_date':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_details.get('deadline')),
                                    timezone=UTC),
                'title':
                bounty_payload.get('title', ''),
                'issue_description':
                bounty_payload.get('description', ' '),
                'balance':
                bounty_details.get('balance'),
                'contract_address':
                bounty_details.get('token'),
                'network':
                bounty_details.get('network'),
                'bounty_type':
                metadata.get('bountyType', ''),
                'funding_organisation':
                metadata.get('fundingOrganisation', ''),
                'project_length':
                metadata.get('projectLength', ''),
                'estimated_hours':
                metadata.get('estimatedHours'),
                'experience_level':
                metadata.get('experienceLevel', ''),
                'project_type':
                schemes.get('project_type', 'traditional'),
                'permission_type':
                schemes.get('permission_type', 'permissionless'),
                'attached_job_description':
                bounty_payload.get('hiring', {}).get('jobDescription', None),
                'is_featured':
                metadata.get('is_featured', False),
                'bounty_owner_github_username':
                bounty_issuer.get('githubUsername', ''),
                'bounty_owner_address':
                bounty_issuer.get('address', ''),
                'bounty_owner_email':
                bounty_issuer.get('email', ''),
                'bounty_owner_name':
                bounty_issuer.get('name', ''),
                'admin_override_suspend_auto_approval':
                not schemes.get('auto_approve_workers', True),
            })
        else:
            latest_old_bounty_dict = latest_old_bounty.to_standard_dict(
                fields=[
                    'web3_created',
                    'github_url',
                    'token_name',
                    'token_address',
                    'privacy_preferences',
                    'expires_date',
                    'title',
                    'issue_description',
                    'balance',
                    'contract_address',
                    'network',
                    'bounty_type',
                    'project_length',
                    'experience_level',
                    'project_type',
                    'permission_type',
                    'attached_job_description',
                    'bounty_owner_github_username',
                    'bounty_owner_address',
                    'bounty_owner_email',
                    'bounty_owner_name',
                    'github_comments',
                    'override_status',
                    'last_comment_date',
                    'snooze_warnings_for_days',
                    'admin_override_and_hide',
                    'admin_override_suspend_auto_approval',
                    'admin_mark_as_remarket_ready',
                    'funding_organisation',
                    'bounty_reserved_for_user',
                    'is_featured',
                ], )
            if latest_old_bounty_dict['bounty_reserved_for_user']:
                latest_old_bounty_dict[
                    'bounty_reserved_for_user'] = Profile.objects.get(
                        pk=latest_old_bounty_dict['bounty_reserved_for_user'])
            bounty_kwargs.update(latest_old_bounty_dict)

        try:
            new_bounty = Bounty.objects.create(**bounty_kwargs)
            new_bounty.fetch_issue_item()
            try:
                issue_kwargs = get_url_dict(new_bounty.github_url)
                new_bounty.github_issue_details = get_gh_issue_details(
                    **issue_kwargs)
            except Exception as e:
                logger.error(e)

            # migrate data objects from old bounty
            if latest_old_bounty:
                # Pull the interested parties off the last old_bounty
                for interest in latest_old_bounty.interested.all().nocache():
                    new_bounty.interested.add(interest)

                # pull the activities off the last old bounty
                for activity in latest_old_bounty.activities.all().nocache():
                    new_bounty.activities.add(activity)

            bounty_reserved_for_user = metadata.get('reservedFor', '')
            if bounty_reserved_for_user:
                new_bounty.reserved_for_user_handle = bounty_reserved_for_user
                new_bounty.save()
                if new_bounty.bounty_reserved_for_user:
                    # notify a user that a bounty has been reserved for them
                    new_reserved_issue('*****@*****.**',
                                       new_bounty.bounty_reserved_for_user,
                                       new_bounty)

            # set cancel date of this bounty
            canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None
            if not canceled_on and new_bounty.status == 'cancelled':
                canceled_on = timezone.now()
            if canceled_on:
                new_bounty.canceled_on = canceled_on
                new_bounty.save()

        except Exception as e:
            print(e, 'encountered during new bounty creation for:', url)
            logger.error(
                f'{e} encountered during new bounty creation for: {url}')
            new_bounty = None

        if fulfillments:
            handle_bounty_fulfillments(fulfillments, new_bounty,
                                       latest_old_bounty)
            for inactive in Bounty.objects.filter(
                    current_bounty=False,
                    github_url=url).nocache().order_by('-created_on'):
                BountyFulfillment.objects.filter(
                    bounty_id=inactive.id).nocache().delete()
    return new_bounty
Exemple #8
0
 def get_natural_value(self):
     token = addr_to_token(self.token_address)
     decimals = token['decimals']
     return float(self.value_in_token) / 10**decimals
Exemple #9
0
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id):
    """Handle new Bounty creation in the event of bounty changes.

    Possible Bounty Stages:
        0: Draft
        1: Active
        2: Dead

    Returns:
        dashboard.models.Bounty: The new Bounty object.

    """
    bounty_issuer = bounty_payload.get('issuer', {})
    metadata = bounty_payload.get('metadata', {})
    # fulfillments metadata will be empty when bounty is first created
    fulfillments = bounty_details.get('fulfillments', {})
    interested_comment_id = None
    submissions_comment_id = None
    interested_comment_id = None

    # start to process out all the bounty data
    url = bounty_payload.get('webReferenceURL')
    if url:
        url = normalize_url(url)
    else:
        raise UnsupportedSchemaException(
            'No webReferenceURL found. Cannot continue!')

    # check conditions for private repos
    if metadata.get('repo_type', None) == 'private' and \
        bounty_payload.get('schemes', {}).get('permission_type', 'permissionless') != 'approval' and \
            bounty_payload.get('schemes', {}).get('project_type', 'traditional') != 'traditional':
        raise UnsupportedSchemaException(
            'The project type or permission does not match for private repo')

    # Check if we have any fulfillments.  If so, check if they are accepted.
    # If there are no fulfillments, accepted is automatically False.
    # Currently we are only considering the latest fulfillment.  Std bounties supports multiple.
    # If any of the fulfillments have been accepted, the bounty is now accepted and complete.
    accepted = any(
        [fulfillment.get('accepted') for fulfillment in fulfillments])
    print('create new bounty with payload:{}'.format(bounty_payload))

    with transaction.atomic():
        old_bounties = old_bounties.distinct().order_by('created_on')
        latest_old_bounty = None
        token_address = bounty_payload.get(
            'tokenAddress', '0x0000000000000000000000000000000000000000')
        token_name = bounty_payload.get('tokenName', '')
        if not token_name:
            token = addr_to_token(token_address)
            if token:
                token_name = token['name']

        for old_bounty in old_bounties:
            if old_bounty.current_bounty:
                submissions_comment_id = old_bounty.submissions_comment
                interested_comment_id = old_bounty.interested_comment
            old_bounty.current_bounty = False
            old_bounty.save()
            latest_old_bounty = old_bounty

        bounty_kwargs = {
            'is_open':
            True if (bounty_details.get('bountyStage') == 1 and not accepted)
            else False,
            'raw_data':
            bounty_details,
            'metadata':
            metadata,
            'current_bounty':
            True,
            'accepted':
            accepted,
            'interested_comment':
            interested_comment_id,
            'submissions_comment':
            submissions_comment_id,
            'standard_bounties_id':
            bounty_id,
            'num_fulfillments':
            len(fulfillments),
            'value_in_token':
            bounty_details.get('fulfillmentAmount', Decimal(1.0)),
            'fee_tx_id':
            bounty_payload.get('fee_tx_id', '0x0'),
            'fee_amount':
            bounty_payload.get('fee_amount', 0)
        }

        coupon_code = bounty_payload.get('coupon_code', None)
        if coupon_code:
            coupon = Coupon.objects.filter(code=coupon_code).first()
            if coupon:
                bounty_kwargs.update({'coupon_code': coupon})

        if not latest_old_bounty:
            print("no latest old bounty")
            schemes = bounty_payload.get('schemes', {})
            unsigned_nda = None
            if bounty_payload.get('unsigned_nda', None):
                unsigned_nda = BountyDocuments.objects.filter(
                    pk=bounty_payload.get('unsigned_nda')).first()
            bounty_kwargs.update({
                # info to xfr over from latest_old_bounty as override fields (this is because sometimes
                # ppl dont login when they first submit issue and it needs to be overridden)
                'web3_created':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_payload.get('created')),
                                    timezone=UTC),
                'last_remarketed':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_payload.get('created')),
                                    timezone=UTC),
                'remarketed_count':
                0,
                'github_url':
                url,
                'token_name':
                token_name,
                'token_address':
                token_address,
                'privacy_preferences':
                bounty_payload.get('privacy_preferences', {}),
                'expires_date':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_details.get('deadline')),
                                    timezone=UTC),
                'title':
                bounty_payload.get('title', ''),
                'issue_description':
                bounty_payload.get('description', ' '),
                'balance':
                bounty_details.get('balance'),
                'contract_address':
                bounty_details.get('token'),
                'network':
                bounty_details.get('network'),
                'bounty_type':
                metadata.get('bountyType', ''),
                'bounty_categories':
                metadata.get('bounty_categories', '').split(','),
                'funding_organisation':
                metadata.get('fundingOrganisation', ''),
                'project_length':
                metadata.get('projectLength', ''),
                'estimated_hours':
                metadata.get('estimatedHours'),
                'experience_level':
                metadata.get('experienceLevel', ''),
                'project_type':
                schemes.get('project_type', 'traditional'),
                'permission_type':
                schemes.get('permission_type', 'permissionless'),
                'attached_job_description':
                bounty_payload.get('hiring', {}).get('jobDescription', None),
                'is_featured':
                metadata.get('is_featured', False),
                'featuring_date':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    metadata.get('featuring_date', 0)),
                                    timezone=UTC),
                'repo_type':
                metadata.get('repo_type', 'public'),
                'unsigned_nda':
                unsigned_nda,
                'bounty_owner_github_username':
                bounty_issuer.get('githubUsername', ''),
                'bounty_owner_address':
                bounty_issuer.get('address', ''),
                'bounty_owner_email':
                bounty_issuer.get('email', ''),
                'bounty_owner_name':
                bounty_issuer.get('name', ''),
                'admin_override_suspend_auto_approval':
                not schemes.get('auto_approve_workers', True),
                'fee_tx_id':
                bounty_payload.get('fee_tx_id', '0x0'),
                'fee_amount':
                bounty_payload.get('fee_amount', 0)
            })
        else:
            # print('latest old bounty found {}'.format(latest_old_bounty))
            latest_old_bounty_dict = latest_old_bounty.to_standard_dict(
                fields=[
                    'web3_created', 'github_url', 'token_name',
                    'token_address', 'privacy_preferences', 'expires_date',
                    'title', 'issue_description', 'balance',
                    'contract_address', 'network', 'bounty_type',
                    'bounty_categories', 'project_length', 'experience_level',
                    'project_type', 'permission_type',
                    'attached_job_description', 'bounty_owner_github_username',
                    'bounty_owner_address', 'bounty_owner_email',
                    'bounty_owner_name', 'github_comments', 'override_status',
                    'last_comment_date', 'snooze_warnings_for_days',
                    'admin_override_and_hide',
                    'admin_override_suspend_auto_approval',
                    'admin_mark_as_remarket_ready', 'funding_organisation',
                    'bounty_reserved_for_user', 'is_featured',
                    'featuring_date', 'fee_tx_id', 'fee_amount', 'repo_type',
                    'unsigned_nda', 'coupon_code', 'admin_override_org_name',
                    'admin_override_org_logo', 'bounty_state'
                ], )
            if latest_old_bounty_dict['bounty_reserved_for_user']:
                latest_old_bounty_dict[
                    'bounty_reserved_for_user'] = Profile.objects.get(
                        pk=latest_old_bounty_dict['bounty_reserved_for_user'])
            if latest_old_bounty_dict.get('bounty_owner_profile'):
                latest_old_bounty_dict[
                    'bounty_owner_profile'] = Profile.objects.get(
                        pk=latest_old_bounty_dict['bounty_owner_profile'])
            if latest_old_bounty_dict['unsigned_nda']:
                latest_old_bounty_dict[
                    'unsigned_nda'] = BountyDocuments.objects.filter(
                        pk=latest_old_bounty_dict['unsigned_nda']).first()
            if latest_old_bounty_dict.get('coupon_code'):
                latest_old_bounty_dict['coupon_code'] = Coupon.objects.get(
                    pk=latest_old_bounty_dict['coupon_code'])

            bounty_kwargs.update(latest_old_bounty_dict)
        try:
            print('new bounty with kwargs:{}'.format(bounty_kwargs))
            new_bounty = Bounty.objects.create(**bounty_kwargs)
            merge_bounty(latest_old_bounty, new_bounty, metadata,
                         bounty_details)
        except Exception as e:
            print(e, 'encountered during new bounty creation for:', url)
            logger.error(
                f'{e} encountered during new bounty creation for: {url}')
            new_bounty = None

    return new_bounty
Exemple #10
0
def amount_in_wei(tokenAddress, amount):
    from dashboard.tokens import addr_to_token
    token = addr_to_token(tokenAddress)
    decimals = token['decimals'] if token else 18
    return float(amount) * 10**decimals
Exemple #11
0
 def get_natural_value(self):
     token = addr_to_token(self.tokenAddress)
     decimals = token['decimals']
     return float(self.amount) / 10**decimals
Exemple #12
0
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id):
    """Handle new Bounty creation in the event of bounty changes.

    Possible Bounty Stages:
        0: Draft
        1: Active
        2: Dead

    Returns:
        dashboard.models.Bounty: The new Bounty object.

    """
    bounty_issuer = bounty_payload.get('issuer', {})
    metadata = bounty_payload.get('metadata', {})
    # fulfillments metadata will be empty when bounty is first created
    fulfillments = bounty_details.get('fulfillments', {})
    interested_comment_id = None
    submissions_comment_id = None
    interested_comment_id = None

    # start to process out all the bounty data
    url = bounty_payload.get('webReferenceURL')
    if url:
        url = normalize_url(url)
    else:
        raise UnsupportedSchemaException(
            'No webReferenceURL found. Cannot continue!')

    # check conditions for private repos
    if metadata.get('repo_type', None) == 'private' and \
        bounty_payload.get('schemes', {}).get('permission_type', 'permissionless') != 'approval' and \
            bounty_payload.get('schemes', {}).get('project_type', 'traditional') != 'traditional':
        raise UnsupportedSchemaException(
            'The project type or permission does not match for private repo')

    # Check if we have any fulfillments.  If so, check if they are accepted.
    # If there are no fulfillments, accepted is automatically False.
    # Currently we are only considering the latest fulfillment.  Std bounties supports multiple.
    # If any of the fulfillments have been accepted, the bounty is now accepted and complete.
    accepted = any(
        [fulfillment.get('accepted') for fulfillment in fulfillments])
    print('create new bounty with payload:{}'.format(bounty_payload))

    with transaction.atomic():
        old_bounties = old_bounties.distinct().order_by('created_on')
        latest_old_bounty = None
        token_address = bounty_payload.get(
            'tokenAddress', '0x0000000000000000000000000000000000000000')
        token_name = bounty_payload.get('tokenName', '')
        if not token_name:
            token = addr_to_token(token_address)
            if token:
                token_name = token['name']

        for old_bounty in old_bounties:
            if old_bounty.current_bounty:
                submissions_comment_id = old_bounty.submissions_comment
                interested_comment_id = old_bounty.interested_comment
            old_bounty.current_bounty = False
            old_bounty.save()
            latest_old_bounty = old_bounty

        bounty_kwargs = {
            'is_open':
            True if (bounty_details.get('bountyStage') == 1 and not accepted)
            else False,
            'raw_data':
            bounty_details,
            'metadata':
            metadata,
            'current_bounty':
            True,
            'accepted':
            accepted,
            'interested_comment':
            interested_comment_id,
            'submissions_comment':
            submissions_comment_id,
            'standard_bounties_id':
            bounty_id,
            'num_fulfillments':
            len(fulfillments),
            'value_in_token':
            bounty_details.get('fulfillmentAmount', Decimal(1.0)),
            'fee_tx_id':
            bounty_payload.get('fee_tx_id', '0x0'),
            'fee_amount':
            bounty_payload.get('fee_amount', 0)
        }
        if not latest_old_bounty:
            print("no latest old bounty")
            schemes = bounty_payload.get('schemes', {})
            unsigned_nda = None
            if bounty_payload.get('unsigned_nda', None):
                unsigned_nda = BountyDocuments.objects.filter(
                    pk=bounty_payload.get('unsigned_nda')).first()
            bounty_kwargs.update({
                # info to xfr over from latest_old_bounty as override fields (this is because sometimes
                # ppl dont login when they first submit issue and it needs to be overridden)
                'web3_created':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_payload.get('created')),
                                    timezone=UTC),
                'github_url':
                url,
                'token_name':
                token_name,
                'token_address':
                token_address,
                'privacy_preferences':
                bounty_payload.get('privacy_preferences', {}),
                'expires_date':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    bounty_details.get('deadline')),
                                    timezone=UTC),
                'title':
                bounty_payload.get('title', ''),
                'issue_description':
                bounty_payload.get('description', ' '),
                'balance':
                bounty_details.get('balance'),
                'contract_address':
                bounty_details.get('token'),
                'network':
                bounty_details.get('network'),
                'bounty_type':
                metadata.get('bountyType', ''),
                'funding_organisation':
                metadata.get('fundingOrganisation', ''),
                'project_length':
                metadata.get('projectLength', ''),
                'estimated_hours':
                metadata.get('estimatedHours'),
                'experience_level':
                metadata.get('experienceLevel', ''),
                'project_type':
                schemes.get('project_type', 'traditional'),
                'permission_type':
                schemes.get('permission_type', 'permissionless'),
                'attached_job_description':
                bounty_payload.get('hiring', {}).get('jobDescription', None),
                'is_featured':
                metadata.get('is_featured', False),
                'featuring_date':
                timezone.make_aware(timezone.datetime.fromtimestamp(
                    metadata.get('featuring_date', 0)),
                                    timezone=UTC),
                'repo_type':
                metadata.get('repo_type', 'public'),
                'unsigned_nda':
                unsigned_nda,
                'bounty_owner_github_username':
                bounty_issuer.get('githubUsername', ''),
                'bounty_owner_address':
                bounty_issuer.get('address', ''),
                'bounty_owner_email':
                bounty_issuer.get('email', ''),
                'bounty_owner_name':
                bounty_issuer.get('name', ''),
                'admin_override_suspend_auto_approval':
                not schemes.get('auto_approve_workers', True),
                'fee_tx_id':
                bounty_payload.get('fee_tx_id', '0x0'),
                'fee_amount':
                bounty_payload.get('fee_amount', 0)
            })
        else:
            print('latest old bounty found {}'.format(latest_old_bounty))
            latest_old_bounty_dict = latest_old_bounty.to_standard_dict(
                fields=[
                    'web3_created', 'github_url', 'token_name',
                    'token_address', 'privacy_preferences', 'expires_date',
                    'title', 'issue_description', 'balance',
                    'contract_address', 'network', 'bounty_type',
                    'project_length', 'experience_level', 'project_type',
                    'permission_type', 'attached_job_description',
                    'bounty_owner_github_username', 'bounty_owner_address',
                    'bounty_owner_email', 'bounty_owner_name',
                    'github_comments', 'override_status', 'last_comment_date',
                    'snooze_warnings_for_days', 'admin_override_and_hide',
                    'admin_override_suspend_auto_approval',
                    'admin_mark_as_remarket_ready', 'funding_organisation',
                    'bounty_reserved_for_user', 'is_featured',
                    'featuring_date', 'fee_tx_id', 'fee_amount', 'repo_type',
                    'unsigned_nda'
                ], )
            if latest_old_bounty_dict['bounty_reserved_for_user']:
                latest_old_bounty_dict[
                    'bounty_reserved_for_user'] = Profile.objects.get(
                        pk=latest_old_bounty_dict['bounty_reserved_for_user'])
            if latest_old_bounty_dict.get('bounty_owner_profile'):
                latest_old_bounty_dict[
                    'bounty_owner_profile'] = Profile.objects.get(
                        pk=latest_old_bounty_dict['bounty_owner_profile'])
            if latest_old_bounty_dict['unsigned_nda']:
                latest_old_bounty_dict[
                    'unsigned_nda'] = BountyDocuments.objects.filter(
                        pk=latest_old_bounty_dict['unsigned_nda']).first()
            bounty_kwargs.update(latest_old_bounty_dict)

        try:
            print('new bounty with kwargs:{}'.format(bounty_kwargs))
            new_bounty = Bounty.objects.create(**bounty_kwargs)
            print('new bounty is:{}'.format(new_bounty.to_standard_dict()))
            new_bounty.fetch_issue_item()
            try:
                issue_kwargs = get_url_dict(new_bounty.github_url)
                new_bounty.github_issue_details = get_gh_issue_details(
                    **issue_kwargs)

            except Exception as e:
                logger.error(e)

            event_tag = metadata.get('eventTag', '')
            if event_tag:
                try:
                    evt = HackathonEvent.objects.filter(
                        name__iexact=event_tag).latest('id')
                    new_bounty.event = evt
                    new_bounty.save()
                except Exception as e:
                    logger.error(e)

            bounty_invitees = metadata.get('invite', '')
            if bounty_invitees and not latest_old_bounty:
                from marketing.mails import share_bounty
                from dashboard.utils import get_bounty_invite_url
                emails = []
                inviter = Profile.objects.get(
                    handle=new_bounty.bounty_owner_github_username)
                invite_url = get_bounty_invite_url(inviter, new_bounty.id)
                msg = "Check out this bounty that pays out " + \
                    str(new_bounty.get_value_true) + new_bounty.token_name + invite_url
                for keyword in new_bounty.keywords_list:
                    msg += " #" + keyword
                for user_id in bounty_invitees:
                    profile = Profile.objects.get(id=int(user_id))
                    bounty_invite = BountyInvites.objects.create(
                        status='pending')
                    bounty_invite.bounty.add(new_bounty)
                    bounty_invite.inviter.add(inviter.user)
                    bounty_invite.invitee.add(profile.user)
                    emails.append(profile.email)
                try:
                    share_bounty(emails, msg, inviter, invite_url, False)
                    response = {
                        'status': 200,
                        'msg': 'email_sent',
                    }
                except Exception as e:
                    logging.exception(e)
                    response = {
                        'status': 500,
                        'msg': 'Email not sent',
                    }
            # migrate data objects from old bounty
            if latest_old_bounty:
                # Pull the interested parties off the last old_bounty
                for interest in latest_old_bounty.interested.all().nocache():
                    new_bounty.interested.add(interest)

                # pull the activities off the last old bounty
                for activity in latest_old_bounty.activities.all().nocache():
                    new_bounty.activities.add(activity)

            bounty_reserved_for_user = metadata.get('reservedFor', '')
            if bounty_reserved_for_user:
                new_bounty.reserved_for_user_handle = bounty_reserved_for_user
                new_bounty.save()
                if new_bounty.bounty_reserved_for_user:
                    # notify a user that a bounty has been reserved for them
                    new_reserved_issue('*****@*****.**',
                                       new_bounty.bounty_reserved_for_user,
                                       new_bounty)

            # set cancel date of this bounty
            canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None
            if not canceled_on and new_bounty.status == 'cancelled':
                canceled_on = timezone.now()
            if canceled_on:
                new_bounty.canceled_on = canceled_on
                new_bounty.save()

            # preserve featured status for bounties where it was set manually
            new_bounty.is_featured = True if latest_old_bounty and latest_old_bounty.is_featured is True else False
            if new_bounty.is_featured == True:
                new_bounty.save()

        except Exception as e:
            print(e, 'encountered during new bounty creation for:', url)
            logger.error(
                f'{e} encountered during new bounty creation for: {url}')
            new_bounty = None

        if fulfillments:
            handle_bounty_fulfillments(fulfillments, new_bounty,
                                       latest_old_bounty)
            for inactive in Bounty.objects.filter(
                    current_bounty=False,
                    github_url=url).nocache().order_by('-created_on'):
                BountyFulfillment.objects.filter(
                    bounty_id=inactive.id).nocache().delete()
    return new_bounty
Exemple #13
0
 def get_natural_value(self):
     token = addr_to_token(self.token_address)
     if not token:
         return 0
     decimals = token.get('decimals', 0)
     return float(self.value_in_token) / 10**decimals
Exemple #14
0
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id):
    """Handle new Bounty creation in the event of bounty changes.

    Possible Bounty Stages:
        0: Draft
        1: Active
        2: Dead

    Returns:
        dashboard.models.Bounty: The new Bounty object.

    """
    bounty_issuer = bounty_payload.get('issuer', {})
    metadata = bounty_payload.get('metadata', {})
    # fulfillments metadata will be empty when bounty is first created
    fulfillments = bounty_details.get('fulfillments', {})
    interested_comment_id = None
    submissions_comment_id = None
    interested_comment_id = None

    # start to process out all the bounty data
    url = bounty_payload.get('webReferenceURL')
    if url:
        url = normalize_url(url)
    else:
        raise UnsupportedSchemaException(
            'No webReferenceURL found. Cannot continue!')

    # Check if we have any fulfillments.  If so, check if they are accepted.
    # If there are no fulfillments, accepted is automatically False.
    # Currently we are only considering the latest fulfillment.  Std bounties supports multiple.
    # If any of the fulfillments have been accepted, the bounty is now accepted and complete.
    accepted = any(
        [fulfillment.get('accepted') for fulfillment in fulfillments])

    with transaction.atomic():
        old_bounties = old_bounties.distinct().order_by('created_on')
        latest_old_bounty = None
        token_address = bounty_payload.get(
            'tokenAddress', '0x0000000000000000000000000000000000000000')
        token_name = bounty_payload.get('tokenName', '')
        if not token_name:
            token = addr_to_token(token_address)
            if token:
                token_name = token['name']

        for old_bounty in old_bounties:
            if old_bounty.current_bounty:
                submissions_comment_id = old_bounty.submissions_comment
                interested_comment_id = old_bounty.interested_comment
            old_bounty.current_bounty = False
            old_bounty.save()
            latest_old_bounty = old_bounty
        try:
            new_bounty = Bounty.objects.create(
                title=bounty_payload.get('title', ''),
                issue_description=bounty_payload.get('description', ' '),
                web3_created=timezone.make_aware(
                    timezone.datetime.fromtimestamp(
                        bounty_payload.get('created')),
                    timezone=UTC),
                value_in_token=bounty_details.get('fulfillmentAmount'),
                token_name=token_name,
                token_address=token_address,
                bounty_type=metadata.get('bountyType', ''),
                project_length=metadata.get('projectLength', ''),
                experience_level=metadata.get('experienceLevel', ''),
                github_url=url,  # Could also use payload.get('webReferenceURL')
                bounty_owner_address=bounty_issuer.get('address', ''),
                bounty_owner_email=bounty_issuer.get('email', ''),
                bounty_owner_github_username=bounty_issuer.get(
                    'githubUsername', ''),
                bounty_owner_name=bounty_issuer.get('name', ''),
                is_open=True if (bounty_details.get('bountyStage') == 1
                                 and not accepted) else False,
                raw_data=bounty_details,
                metadata=metadata,
                current_bounty=True,
                contract_address=bounty_details.get('token'),
                network=bounty_details.get('network'),
                accepted=accepted,
                interested_comment=interested_comment_id,
                submissions_comment=submissions_comment_id,
                project_type=bounty_payload.get('schemes', {}).get(
                    'project_type', 'traditional'),
                permission_type=bounty_payload.get('schemes', {}).get(
                    'permission_type', 'permissionless'),
                privacy_preferences=bounty_payload.get('privacy_preferences',
                                                       {}),
                # These fields are after initial bounty creation, in bounty_details.js
                expires_date=timezone.make_aware(
                    timezone.datetime.fromtimestamp(
                        bounty_details.get('deadline')),
                    timezone=UTC),
                standard_bounties_id=bounty_id,
                balance=bounty_details.get('balance'),
                num_fulfillments=len(fulfillments),
                # info to xfr over from latest_old_bounty
                github_comments=latest_old_bounty.github_comments
                if latest_old_bounty else 0,
                override_status=latest_old_bounty.override_status
                if latest_old_bounty else '',
                last_comment_date=latest_old_bounty.last_comment_date
                if latest_old_bounty else None,
                snooze_warnings_for_days=latest_old_bounty.
                snooze_warnings_for_days if latest_old_bounty else 0,
                admin_override_and_hide=latest_old_bounty.
                admin_override_and_hide if latest_old_bounty else 0,
            )
            new_bounty.fetch_issue_item()

            # Pull the interested parties off the last old_bounty
            if latest_old_bounty:
                for interest in latest_old_bounty.interested.all():
                    new_bounty.interested.add(interest)

            # set cancel date of this bounty
            canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None
            if not canceled_on and new_bounty.status == 'cancelled':
                canceled_on = timezone.now()
            if canceled_on:
                new_bounty.canceled_on = canceled_on
                new_bounty.save()

        except Exception as e:
            print(e, 'encountered during new bounty creation for:', url)
            logging.error(
                f'{e} encountered during new bounty creation for: {url}')
            new_bounty = None

        if fulfillments:
            handle_bounty_fulfillments(fulfillments, new_bounty,
                                       latest_old_bounty)
            for inactive in Bounty.objects.filter(
                    current_bounty=False,
                    github_url=url).order_by('-created_on'):
                BountyFulfillment.objects.filter(
                    bounty_id=inactive.id).delete()
    return new_bounty
Exemple #15
0
 def test_addr_to_token_invalid(self):
     """Test the dashboard token lookup utility with an invalid token."""
     token = addr_to_token('0xGITCOIN')
     assert isinstance(token, bool)
     assert token is False