def issue_details(request): """Determine the Github issue keywords of the specified Github issue or PR URL. Todo: * Modify the view to only use the Github API (remove BeautifulSoup). * Simplify the view logic. Returns: JsonResponse: A JSON response containing the Github issue or PR keywords. """ from dashboard.utils import clean_bounty_url response = {} token = request.GET.get('token', None) url = request.GET.get('url') url_val = URLValidator() hackathon_slug = request.GET.get('hackathon_slug') duplicates = request.GET.get('duplicates', False) network = request.GET.get('network', 'mainnet') if hackathon_slug: sponsor_profiles = HackathonEvent.objects.filter(slug__iexact=hackathon_slug).prefetch_related('sponsor_profiles').values_list('sponsor_profiles__handle', flat=True) org_issue = org_name(url).lower() if org_issue not in sponsor_profiles: message = 'This issue is not under any sponsor repository' return JsonResponse({'status':'false','message':message}, status=404) if duplicates: if Bounty.objects.filter(github_url=url, network=network).exists(): message = 'Bounty already exists for this github issue' response = { 'status': 422, 'message': message } return JsonResponse(response, status=422) try: url_val(url) except ValidationError: response['message'] = 'invalid arguments' return JsonResponse(response) if url.lower()[:19] != 'https://github.com/': response['message'] = 'invalid arguments' return JsonResponse(response) url_dict = get_url_dict(clean_bounty_url(url)) try: if url_dict: response = get_gh_issue_details(token=token, **url_dict) else: response['message'] = 'could not parse Github url' except Exception as e: logger.warning(e) message = 'could not pull back remote response' return JsonResponse({'status':'false','message':message}, status=404) return JsonResponse(response)
def issue_details(request): """Determine theissue keywords of the specified issue or PR URL. Todo: * Modify the view to only use the Github API (remove BeautifulSoup). * Simplify the view logic. Returns: JsonResponse: A JSON response containing the issue or PR keywords. """ from dashboard.utils import clean_bounty_url response = {} token = request.GET.get('token', None) url = request.GET.get('url') url_val = URLValidator() try: url_val(url) except ValidationError: response['message'] = 'invalid arguments' return JsonResponse(response) if url.lower()[:19] != 'https://github.com/' and url.lower( )[:19] != 'https://gitlab.com/': response['message'] = 'invalid arguments' return JsonResponse(response) try: url_dict = get_url_dict(clean_bounty_url(url)) if url_dict: logger.info(url_dict) response = get_issue_details(token=token, **url_dict) else: response['message'] = 'could not parse url' except Exception as e: logger.warning(e) response['message'] = 'could not pull back remote response' return JsonResponse(response)
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
def merge_bounty(latest_old_bounty, new_bounty, metadata, bounty_details, verbose=True): if verbose: 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) if latest_old_bounty and latest_old_bounty.event: new_bounty.event = latest_old_bounty.event new_bounty.save() else: 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)) if not profile.user: continue 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', '') release_to_public_after = metadata.get('releaseAfter', '') if bounty_reserved_for_user and release_to_public_after: new_bounty.reserved_for_user_from = timezone.now() if release_to_public_after == "3-days": new_bounty.reserved_for_user_expiration = new_bounty.reserved_for_user_from + timezone.timedelta( days=3) elif release_to_public_after == "1-week": new_bounty.reserved_for_user_expiration = new_bounty.reserved_for_user_from + timezone.timedelta( weeks=1) new_bounty.reserved_for_user_handle = bounty_reserved_for_user new_bounty.save() if new_bounty.bounty_reserved_for_user and new_bounty.status == 'reserved': # 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() # migrate fulfillments, and only take the ones from # fulfillments metadata will be empty when bounty is first created fulfillments = bounty_details.get('fulfillments', {}) if fulfillments: handle_bounty_fulfillments(fulfillments, new_bounty, latest_old_bounty) url = normalize_url(new_bounty.github_url) 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() # 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() if latest_old_bounty: latest_old_bounty.current_bounty = False latest_old_bounty.save()
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
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( 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, # These fields are after initial bounty creation, in bounty_details.js standard_bounties_id=bounty_id, num_fulfillments=len(fulfillments), value_in_token=bounty_details.get('fulfillmentAmount'), # 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) if not latest_old_bounty else latest_old_bounty.web3_created, github_url=url if not latest_old_bounty else latest_old_bounty.github_url, token_name=token_name if not latest_old_bounty else latest_old_bounty.token_name, token_address=token_address if not latest_old_bounty else latest_old_bounty.token_address, privacy_preferences=bounty_payload.get( 'privacy_preferences', {}) if not latest_old_bounty else latest_old_bounty.privacy_preferences, expires_date=timezone.make_aware( timezone.datetime.fromtimestamp( bounty_details.get('deadline')), timezone=UTC) if not latest_old_bounty else latest_old_bounty.expires_date, title=bounty_payload.get('title', '') if not latest_old_bounty else latest_old_bounty.title, issue_description=bounty_payload.get('description', ' ') if not latest_old_bounty else latest_old_bounty.issue_description, balance=bounty_details.get('balance') if not latest_old_bounty else latest_old_bounty.balance, contract_address=bounty_details.get('token') if not latest_old_bounty else latest_old_bounty.contract_address, network=bounty_details.get('network') if not latest_old_bounty else latest_old_bounty.network, bounty_type=metadata.get('bountyType', '') if not latest_old_bounty else latest_old_bounty.bounty_type, project_length=metadata.get('projectLength', '') if not latest_old_bounty else latest_old_bounty.project_length, experience_level=metadata.get('experienceLevel', '') if not latest_old_bounty else latest_old_bounty.experience_level, project_type=bounty_payload.get('schemes', {}).get( 'project_type', 'traditional') if not latest_old_bounty else latest_old_bounty.project_type, permission_type=bounty_payload.get('schemes', {}).get( 'permission_type', 'permissionless') if not latest_old_bounty else latest_old_bounty.permission_type, attached_job_description=bounty_payload.get('hiring', {}).get( 'jobDescription', None) if not latest_old_bounty else latest_old_bounty.attached_job_description, bounty_owner_github_username=bounty_issuer.get( 'githubUsername', '') if not latest_old_bounty else latest_old_bounty.bounty_owner_github_username, bounty_owner_address=bounty_issuer.get('address', '') if not latest_old_bounty else latest_old_bounty.bounty_owner_address, bounty_owner_email=bounty_issuer.get('email', '') if not latest_old_bounty else latest_old_bounty.bounty_owner_email, bounty_owner_name=bounty_issuer.get('name', '') if not latest_old_bounty else latest_old_bounty.bounty_owner_name, # 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, admin_override_suspend_auto_approval=latest_old_bounty. admin_override_suspend_auto_approval if latest_old_bounty else 0, admin_mark_as_remarket_ready=latest_old_bounty. admin_mark_as_remarket_ready if latest_old_bounty else 0, ) 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(): new_bounty.interested.add(interest) # pull the activities off the last old bounty for activity in latest_old_bounty.activities.all(): new_bounty.activities.add(activity) # 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