def send_tip_3(request): """Handle the third stage of sending a tip (the POST). Returns: JsonResponse: response with success state. """ response = { 'status': 'OK', 'message': _('Tip Created'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' primary_from_email = request.user.email if is_user_authenticated else '' access_token = request.user.profile.get_access_token() if is_user_authenticated and request.user.profile else '' params = json.loads(request.body) to_username = params['username'].lstrip('@') to_emails = get_emails_by_category(to_username) primary_email = '' if params.get('email'): primary_email = params['email'] elif to_emails.get('primary', None): primary_email = to_emails['primary'] elif to_emails.get('github_profile', None): primary_email = to_emails['github_profile'] else: if len(to_emails.get('events', None)): primary_email = to_emails['events'][0] else: print("TODO: no email found. in the future, we should handle this case better because it's GOING to end up as a support request") if primary_email and isinstance(primary_email, list): primary_email = primary_email[0] # If no primary email in session, try the POST data. If none, fetch from GH. if params.get('fromEmail'): primary_from_email = params['fromEmail'] elif access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) expires_date = timezone.now() + timezone.timedelta(seconds=params['expires_date']) # metadata metadata = params['metadata'] metadata['user_agent'] = request.META.get('HTTP_USER_AGENT', '') # db mutations tip = Tip.objects.create( primary_email=primary_email, emails=to_emails, tokenName=params['tokenName'], amount=params['amount'], comments_priv=params['comments_priv'], comments_public=params['comments_public'], ip=get_ip(request), expires_date=expires_date, github_url=params['github_url'], from_name=params['from_name'] if params['from_name'] != 'False' else '', from_email=params['from_email'], from_username=from_username, username=params['username'], network=params.get('network', 'unknown'), tokenAddress=params['tokenAddress'], from_address=params['from_address'], is_for_bounty_fulfiller=params['is_for_bounty_fulfiller'], metadata=metadata, recipient_profile=get_profile(to_username), sender_profile=get_profile(from_username), ) return JsonResponse(response)
def receive_bulk(request, secret): coupons = BulkTransferCoupon.objects.filter(secret=secret) if not coupons.exists(): raise Http404 coupon = coupons.first() _class = request.GET.get('class', '') if coupon.num_uses_remaining <= 0: messages.info(request, f'Sorry but the coupon for a free kudos has been used already. Contact the person who sent you the coupon link, or you can still purchase one on this page.') return redirect(coupon.token.url) error = False if request.POST: if request.user.is_anonymous: error = "You must login." if not error: submit_later = (recommend_min_gas_price_to_confirm_in_time(1)) > 10 and not coupon.is_paid_right_now submit_later = False success, error, _ = redeem_bulk_coupon(coupon, request.user.profile, request.POST.get('forwarding_address'), get_ip(request), request.POST.get('save_addr'), submit_later=submit_later) if error: messages.error(request, error) kudos_transfer = None if request.user.is_authenticated: redemptions = BulkTransferRedemption.objects.filter(redeemed_by=request.user.profile, coupon=coupon) if redemptions.exists(): kudos_transfer = redemptions.first().kudostransfer title = f"Redeem {coupon.token.humanized_name} Kudos from @{coupon.sender_profile.handle}" desc = f"This Kudos has been AirDropped to you. About this Kudos: {coupon.token.description}" tweet_text = f"I just got a {coupon.token.humanized_name} Kudos on @gitcoin. " if not request.GET.get('tweet', None) else request.GET.get('tweet') gas_amount = round(0.00035 * 1.3 * float(recommend_min_gas_price_to_confirm_in_time(1)), 4) params = { 'title': title, 'card_title': title, 'card_desc': desc, 'error': error, 'avatar_url': coupon.token.img_url, 'coupon': coupon, 'user': request.user, 'class': _class, 'gas_amount': gas_amount, 'is_authed': request.user.is_authenticated, 'kudos_transfer': kudos_transfer, 'tweet_text': urllib.parse.quote_plus(tweet_text), 'tweet_url': coupon.token.url if not request.GET.get('tweet_url') else request.GET.get('tweet_url'), } return TemplateResponse(request, 'transaction/receive_bulk.html', params)
def send_tip_3(request): """Handle the third stage of sending a tip (the POST) Returns: JsonResponse: response with success state. """ response = { 'status': 'OK', 'message': _('Tip Created'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' primary_from_email = request.user.email if is_user_authenticated else '' access_token = request.user.profile.get_access_token( ) if is_user_authenticated else '' to_emails = [] params = json.loads(request.body) to_username = params['username'].lstrip('@') to_emails = get_emails_master(to_username) if params.get('email'): to_emails.append(params['email']) # If no primary email in session, try the POST data. If none, fetch from GH. if params.get('fromEmail'): primary_from_email = params['fromEmail'] elif access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) to_emails = list(set(to_emails)) expires_date = timezone.now() + timezone.timedelta( seconds=params['expires_date']) # db mutations tip = Tip.objects.create( emails=to_emails, tokenName=params['tokenName'], amount=params['amount'], comments_priv=params['comments_priv'], comments_public=params['comments_public'], ip=get_ip(request), expires_date=expires_date, github_url=params['github_url'], from_name=params['from_name'], from_email=params['from_email'], from_username=from_username, username=params['username'], network=params['network'], tokenAddress=params['tokenAddress'], from_address=params['from_address'], is_for_bounty_fulfiller=params['is_for_bounty_fulfiller'], metadata=params['metadata'], recipient_profile=get_profile(to_username), sender_profile=get_profile(from_username), ) is_over_tip_tx_limit = False is_over_tip_weekly_limit = False max_per_tip = request.user.profile.max_tip_amount_usdt_per_tx if request.user.is_authenticated and request.user.profile else 500 if tip.value_in_usdt_now: is_over_tip_tx_limit = tip.value_in_usdt_now > max_per_tip if request.user.is_authenticated and request.user.profile: tips_last_week_value = tip.value_in_usdt_now tips_last_week = Tip.objects.exclude(txid='').filter( sender_profile=get_profile(from_username), created_on__gt=timezone.now() - timezone.timedelta(days=7)) for this_tip in tips_last_week: if this_tip.value_in_usdt_now: tips_last_week_value += this_tip.value_in_usdt_now is_over_tip_weekly_limit = tips_last_week_value > request.user.profile.max_tip_amount_usdt_per_week if is_over_tip_tx_limit: response['status'] = 'error' response['message'] = _( 'This tip is over the per-transaction limit of $') + str( max_per_tip) + ( '. Please try again later or contact support.') elif is_over_tip_weekly_limit: response['status'] = 'error' response['message'] = _( 'You are over the weekly tip send limit of $') + str( request.user.profile.max_tip_amount_usdt_per_week) + ( '. Please try again later or contact support.') return JsonResponse(response)
def account_settings(request): """Display and save user's Account settings. Returns: TemplateResponse: The user's Account settings template response. """ msg = '' profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not profile or not is_logged_in: login_redirect = redirect('/login/github?next=' + request.get_full_path()) return login_redirect if request.POST: if 'preferred_payout_address' in request.POST.keys(): profile.preferred_payout_address = request.POST.get( 'preferred_payout_address', '') profile.save() msg = _('Updated your Address') elif request.POST.get('disconnect', False): profile.github_access_token = '' profile = record_form_submission(request, profile, 'account-disconnect') profile.email = '' profile.save() create_user_action(profile.user, 'account_disconnected', request) messages.success( request, _('Your account has been disconnected from Github')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect elif request.POST.get('delete', False): # remove profile profile.hide_profile = True profile = record_form_submission(request, profile, 'account-delete') profile.email = '' profile.save() # remove email try: client = MailChimp(mc_user=settings.MAILCHIMP_USER, mc_api=settings.MAILCHIMP_API_KEY) result = client.search_members.get(query=es.email) subscriber_hash = result['exact_matches']['members'][0]['id'] client.lists.members.delete( list_id=settings.MAILCHIMP_LIST_ID, subscriber_hash=subscriber_hash, ) except Exception as e: logger.exception(e) if es: es.delete() request.user.delete() AccountDeletionRequest.objects.create(handle=profile.handle, profile={ 'ip': get_ip(request), }) profile.delete() messages.success(request, _('Your account has been deleted.')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect else: msg = _('Error: did not understand your request') context = { 'is_logged_in': is_logged_in, 'nav': 'internal', 'active': '/settings/account', 'title': _('Account Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': msg, } return TemplateResponse(request, 'settings/account.html', context)
def get_queryset(self): """Get the queryset for Bounty. Returns: QuerySet: The Bounty queryset. """ param_keys = self.request.query_params.keys() queryset = Bounty.objects.prefetch_related( 'fulfillments', 'interested', 'interested__profile', 'activities', 'event') if 'not_current' not in param_keys: queryset = queryset.current() queryset = queryset.order_by('-web3_created') # filtering event_tag = self.request.query_params.get('event_tag', '') if event_tag: if event_tag == 'all': pass else: try: evt = HackathonEvent.objects.filter(slug__iexact=event_tag).latest('id') queryset = queryset.filter(event__pk=evt.pk) except HackathonEvent.DoesNotExist: return Bounty.objects.none() # else: # queryset = queryset.filter(event=None) for key in ['raw_data', 'experience_level', 'project_length', 'bounty_type', 'bounty_categories', 'bounty_owner_address', 'idx_status', 'network', 'bounty_owner_github_username', 'standard_bounties_id', 'permission_type', 'project_type', 'pk']: if key in param_keys: # special hack just for looking up bounties posted by a certain person request_key = key if key != 'bounty_owner_address' else 'coinbase' val = self.request.query_params.get(request_key, '') values = val.strip().split(',') values = [value for value in values if value and val.strip()] if values: _queryset = queryset.none() for value in values: args = {} args[f'{key}__icontains'] = value.strip() _queryset = _queryset | queryset.filter(**args) queryset = _queryset if 'reserved_for_user_handle' in param_keys: handle = self.request.query_params.get('reserved_for_user_handle', '') if handle: try: profile = Profile.objects.filter(handle=handle.lower()).first() queryset = queryset.filter(bounty_reserved_for_user=profile) except: logger.warning(f'reserved_for_user_handle: Unknown handle: ${handle}') # filter by PK if 'pk__gt' in param_keys: queryset = queryset.filter(pk__gt=self.request.query_params.get('pk__gt')) # Filter by a list of PKs if 'pk__in' in param_keys: try: list_of_pks = self.request.query_params.get('pk__in').split(',') queryset = queryset.filter(pk__in=list_of_pks) except Exception: pass # filter by standard_bounties_id if 'standard_bounties_id__in' in param_keys: statuses = self.request.query_params.get('standard_bounties_id__in').split(',') queryset = queryset.filter(standard_bounties_id__in=statuses) # filter by statuses if 'status__in' in param_keys: statuses = self.request.query_params.get('status__in').split(',') queryset = queryset.filter(idx_status__in=statuses) applicants = self.request.query_params.get('applicants') if applicants == '0': queryset = queryset.annotate( interested_count=Count("interested") ).filter(interested_count=0) elif applicants == '1-5': queryset = queryset.annotate( interested_count=Count("interested") ).filter(interested_count__gte=1).filter(interested_count__lte=5) # filter by who is interested if 'started' in param_keys: queryset = queryset.filter(interested__profile__handle__in=[self.request.query_params.get('started')]) # filter by is open or not if 'is_open' in param_keys: queryset = queryset.filter(is_open=self.request.query_params.get('is_open', '').lower() == 'true') queryset = queryset.filter(expires_date__gt=datetime.now()) # filter by urls if 'github_url' in param_keys: urls = self.request.query_params.get('github_url').split(',') queryset = queryset.filter(github_url__in=urls) # filter by orgs if 'org' in param_keys: val = self.request.query_params.get('org', '') values = val.strip().split(',') values = [value for value in values if value and val.strip()] if values: _queryset = queryset.none() for value in values: org = value.strip() _queryset = _queryset | queryset.filter(github_url__icontains=f'https://github.com/{org}') queryset = _queryset # Retrieve all fullfilled bounties by fulfiller_username if 'fulfiller_github_username' in param_keys: queryset = queryset.filter( fulfillments__profile__handle__iexact=self.request.query_params.get('fulfiller_github_username') ) # Retrieve all DONE fullfilled bounties by fulfiller_username if 'fulfiller_github_username_done' in param_keys: queryset = queryset.filter( fulfillments__profile__handle__iexact=self.request.query_params.get('fulfiller_github_username'), fulfillments__accepted=True, ) # Retrieve all interested bounties by profile handle if 'interested_github_username' in param_keys: queryset = queryset.filter( interested__profile__handle=self.request.query_params.get('interested_github_username').lower() ) # Retrieve all mod bounties. # TODO: Should we restrict this to staff only..? Technically I don't think we're worried about that atm? if 'moderation_filter' in param_keys: mod_filter = self.request.query_params.get('moderation_filter') if mod_filter == 'needs_review': queryset = queryset.needs_review() elif mod_filter == 'warned': queryset = queryset.warned() elif mod_filter == 'escalated': queryset = queryset.escalated() elif mod_filter == 'closed_on_github': queryset = queryset.closed() elif mod_filter == 'hidden': queryset = queryset.hidden() elif mod_filter == 'not_started': queryset = queryset.not_started() # All Misc Api things if 'misc' in param_keys: if self.request.query_params.get('misc') == 'hiring': queryset = queryset.exclude(attached_job_description__isnull=True).exclude(attached_job_description='') if 'event' in param_keys: queryset = queryset.filter( repo_type=self.request.query_params.get('event'), ) # Keyword search to search all comma separated keywords queryset_original = queryset if 'keywords' in param_keys: for index, keyword in enumerate(self.request.query_params.get('keywords').split(',')): if index == 0: queryset = queryset_original.keyword(keyword) else: queryset |= queryset_original.keyword(keyword) if 'is_featured' in param_keys: queryset = queryset.filter( is_featured=self.request.query_params.get('is_featured'), is_open=True, ) if 'repo_type' in param_keys: queryset = queryset.filter( repo_type=self.request.query_params.get('repo_type'), ) # order order_by = self.request.query_params.get('order_by') if order_by and order_by != 'null': if order_by == 'recently_marketed': queryset = queryset.order_by(F('last_remarketed').desc(nulls_last = True), '-web3_created') else: queryset = queryset.order_by(order_by) queryset = queryset.distinct() # offset / limit if 'is_featured' not in param_keys: limit = int(self.request.query_params.get('limit', 5)) max_bounties = 100 if limit > max_bounties: limit = max_bounties offset = self.request.query_params.get('offset', 0) if limit: start = int(offset) end = start + int(limit) queryset = queryset[start:end] data = dict(self.request.query_params) data.pop('is_featured', None) # save search history, but only not is_featured if 'is_featured' not in param_keys: if self.request.user and self.request.user.is_authenticated: data['nonce'] = int(time.time() * 1000000) try: SearchHistory.objects.update_or_create( search_type='bounty', user=self.request.user, data=data, ip_address=get_ip(self.request) ) except Exception as e: logger.debug(e) pass # increment view counts pks = [ele.pk for ele in queryset] if len(pks): view_type = 'individual' if len(pks) == 1 else 'list' increment_view_count.delay(pks, queryset[0].content_type, self.request.user.id, view_type) return queryset
def send_tip_2(request): if request.body != '': status = 'OK' message = 'Notification has been sent' params = json.loads(request.body) emails = [] #basic validation username = params['username'] #get emails if params['email']: emails.append(params['email']) gh_user = get_github_user(username) user_full_name = gh_user['name'] if gh_user.get('email', False): emails.append(gh_user['email']) gh_user_events = get_github_user(username, '/events/public') for event in gh_user_events: commits = event.get('payload', {}).get('commits', []) for commit in commits: email = commit.get('author', {}).get('email', None) #print(event['actor']['display_login'].lower() == username.lower()) #print(commit['author']['name'].lower() == user_full_name.lower()) #print('========') if email and \ event['actor']['display_login'].lower() == username.lower() and \ commit['author']['name'].lower() == user_full_name.lower() and \ 'noreply.github.com' not in email and \ email not in emails: emails.append(email) expires_date = timezone.now() + timezone.timedelta( seconds=params['expires_date']) #db mutations tip = Tip.objects.create( emails=emails, url=params['url'], tokenName=params['tokenName'], amount=params['amount'], comments_priv=params['comments_priv'], comments_public=params['comments_public'], ip=get_ip(request), expires_date=expires_date, github_url=params['github_url'], from_name=params['from_name'], from_email=params['from_email'], username=params['username'], network=params['network'], tokenAddress=params['tokenAddress'], txid=params['txid'], ) #notifications did_post_to_github = maybe_market_tip_to_github(tip) maybe_market_tip_to_slack(tip, 'new_tip', tip.txid) tip_email(tip, set(emails), True) if len(emails) == 0: status = 'error' message = 'Uh oh! No email addresses for this user were found via Github API. Youll have to let the tipee know manually about their tip.' #http response response = { 'status': status, 'message': message, } return JsonResponse(response) params = { 'issueURL': request.GET.get('source'), 'class': 'send2', 'title': 'Send Tip', 'recommend_gas_price': recommend_min_gas_price_to_confirm_in_time( confirm_time_minutes_target), } return TemplateResponse(request, 'yge/send2.html', params)
def send_tip_2(request): """Handle the second stage of sending a tip. TODO: * Convert this view-based logic to a django form. Returns: JsonResponse: If submitting tip, return response with success state. TemplateResponse: Render the submission form. """ from_username = request.session.get('handle', '') primary_from_email = request.session.get('email', '') access_token = request.session.get('access_token') to_emails = [] if request.body: # http response response = { 'status': 'OK', 'message': 'Notification has been sent', } params = json.loads(request.body) to_username = params['username'].lstrip('@') try: to_profile = Profile.objects.get(handle__iexact=to_username) if to_profile.email: to_emails.append(to_profile.email) if to_profile.github_access_token: to_emails = get_github_emails(to_profile.github_access_token) except Profile.DoesNotExist: pass if params.get('email'): to_emails.append(params['email']) # If no primary email in session, try the POST data. If none, fetch from GH. if params.get('fromEmail'): primary_from_email = params['fromEmail'] elif access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) to_emails = list(set(to_emails)) expires_date = timezone.now() + timezone.timedelta( seconds=params['expires_date']) # db mutations tip = Tip.objects.create( emails=to_emails, url=params['url'], tokenName=params['tokenName'], amount=params['amount'], comments_priv=params['comments_priv'], comments_public=params['comments_public'], ip=get_ip(request), expires_date=expires_date, github_url=params['github_url'], from_name=params['from_name'], from_email=params['from_email'], from_username=from_username, username=params['username'], network=params['network'], tokenAddress=params['tokenAddress'], txid=params['txid'], from_address=params['from_address'], ) # notifications maybe_market_tip_to_github(tip) maybe_market_tip_to_slack(tip, 'new_tip') maybe_market_tip_to_email(tip, to_emails) if not to_emails: response['status'] = 'error' response[ 'message'] = 'Uh oh! No email addresses for this user were found via Github API. Youll have to let the tipee know manually about their tip.' return JsonResponse(response) params = { 'issueURL': request.GET.get('source'), 'class': 'send2', 'title': 'Send Tip', 'recommend_gas_price': recommend_min_gas_price_to_confirm_in_time( confirm_time_minutes_target), 'from_email': primary_from_email, 'from_handle': from_username, } return TemplateResponse(request, 'yge/send2.html', params)
def receive_bulk(request, secret): coupons = BulkTransferCoupon.objects.filter(secret=secret) if not coupons.exists(): raise Http404 coupon = coupons.first() if coupon.num_uses_remaining <= 0: raise PermissionDenied kudos_transfer = None if request.user.is_authenticated: redemptions = BulkTransferRedemption.objects.filter( redeemed_by=request.user.profile, coupon=coupon) if redemptions.exists(): kudos_transfer = redemptions.first().kudostransfer if request.POST: address = Web3.toChecksumAddress( request.POST.get('forwarding_address')) user = request.user profile = user.profile save_addr = request.POST.get('save_addr') ip_address = get_ip(request) # handle form submission if save_addr: profile.preferred_payout_address = address profile.save() kudos_contract_address = Web3.toChecksumAddress( settings.KUDOS_CONTRACT_MAINNET) kudos_owner_address = Web3.toChecksumAddress( settings.KUDOS_OWNER_ACCOUNT) w3 = get_web3(coupon.token.contract.network) contract = w3.eth.contract( Web3.toChecksumAddress(kudos_contract_address), abi=kudos_abi()) tx = contract.functions.clone( address, coupon.token.token_id, 1).buildTransaction({ 'nonce': get_nonce(coupon.token.contract.network, kudos_owner_address), 'gas': 500000, 'gasPrice': int(recommend_min_gas_price_to_confirm_in_time(5) * 10**9), 'value': int(coupon.token.price_finney / 1000.0 * 10**18), }) signed = w3.eth.account.signTransaction(tx, settings.KUDOS_PRIVATE_KEY) txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex() with transaction.atomic(): kudos_transfer = KudosTransfer.objects.create( emails=[request.user.email], # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=coupon.token, amount=0, comments_public=coupon.comments_to_put_in_kudos_transfer, ip=ip_address, github_url='', from_name=coupon.sender_profile.handle, from_email='', from_username=coupon.sender_profile.handle, username=profile.handle, network=coupon.token.contract.network, from_address=settings.KUDOS_OWNER_ACCOUNT, is_for_bounty_fulfiller=False, metadata={'coupon_redemption': True}, recipient_profile=profile, sender_profile=coupon.sender_profile, txid=txid, receive_txid=txid, ) # save to DB BulkTransferRedemption.objects.create( coupon=coupon, redeemed_by=profile, ip_address=ip_address, kudostransfer=kudos_transfer, ) coupon.num_uses_remaining -= 1 coupon.current_uses += 1 title = f"Redeem AirDropped *{coupon.token.humanized_name}* Kudos" desc = f"This Kudos has been AirDropped to you. About this Kudos: {coupon.token.description}" params = { 'title': title, 'card_title': title, 'card_desc': desc, 'avatar_url': coupon.token.img_url, 'coupon': coupon, 'user': request.user, 'is_authed': request.user.is_authenticated, 'kudos_transfer': kudos_transfer, } return TemplateResponse(request, 'transaction/receive_bulk.html', params)
def account_settings(request): """Display and save user's Account settings. Returns: TemplateResponse: The user's Account settings template response. """ msg = '' profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not profile or not is_logged_in: login_redirect = redirect('/login/github?next=' + request.get_full_path()) return login_redirect if request.POST: if 'persona_is_funder' or 'persona_is_hunter' in request.POST.keys(): profile.persona_is_funder = bool( request.POST.get('persona_is_funder', False)) profile.persona_is_hunter = bool( request.POST.get('persona_is_hunter', False)) profile.save() if 'preferred_payout_address' in request.POST.keys(): eth_address = request.POST.get('preferred_payout_address', '') if not is_valid_eth_address(eth_address): eth_address = profile.preferred_payout_address profile.preferred_payout_address = eth_address profile.save() msg = _('Updated your Address') elif request.POST.get('export', False): export_type = request.POST.get('export_type', False) response = HttpResponse(content_type='text/csv') name = f"gitcoin_{export_type}_{timezone.now().strftime('%Y_%m_%dT%H_00_00')}" response[ 'Content-Disposition'] = f'attachment; filename="{name}.csv"' writer = csv.writer(response) writer.writerow( ['id', 'date', 'From', 'To', 'Type', 'Value In USD', 'url']) profile = request.user.profile earnings = profile.earnings if export_type == 'earnings' else profile.sent_earnings earnings = earnings.all().order_by('-created_on') for earning in earnings: writer.writerow([ earning.pk, earning.created_on.strftime("%Y-%m-%dT%H:00:00"), earning.from_profile.handle if earning.from_profile else '*', earning.to_profile.handle if earning.to_profile else '*', earning.source_type.model_class(), earning.value_usd, earning.url ]) return response elif request.POST.get('disconnect', False): profile.github_access_token = '' profile = record_form_submission(request, profile, 'account-disconnect') profile.email = '' profile.save() create_user_action(profile.user, 'account_disconnected', request) redirect_url = f'https://www.github.com/settings/connections/applications/{settings.GITHUB_CLIENT_ID}' logout(request) logout_redirect = redirect(redirect_url) logout_redirect[ 'Cache-Control'] = 'max-age=0 no-cache no-store must-revalidate' return logout_redirect elif request.POST.get('delete', False): # remove profile profile.hide_profile = True profile = record_form_submission(request, profile, 'account-delete') profile.email = '' profile.save() # remove email delete_user_from_mailchimp(es.email) if es: es.delete() request.user.delete() AccountDeletionRequest.objects.create(handle=profile.handle, profile={ 'ip': get_ip(request), }) profile.avatar_baseavatar_related.all().delete() try: profile.delete() except: profile.github_access_token = '' profile.user = None profile.hide_profile = True profile.save() messages.success(request, _('Your account has been deleted.')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect else: msg = _('Error: did not understand your request') context = { 'is_logged_in': is_logged_in, 'nav': 'home', 'active': '/settings/account', 'title': _('Account Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': msg, } return TemplateResponse(request, 'settings/account.html', context)
def grants(request): """Handle grants explorer.""" limit = request.GET.get('limit', 6) page = request.GET.get('page', 1) sort = request.GET.get('sort_option', '-created_on') network = request.GET.get('network', 'mainnet') keyword = request.GET.get('keyword', '') state = request.GET.get('state', 'active') _grants = None if state == 'active': _grants = Grant.objects.filter( network=network, hidden=False).active().keyword(keyword).order_by(sort) else: _grants = Grant.objects.filter( network=network, hidden=False).keyword(keyword).order_by(sort) paginator = Paginator(_grants, limit) grants = paginator.get_page(page) partners = MatchPledge.objects.filter(active=True) grant_amount = 0 grant_stats = Stat.objects.filter(key='grants', ).order_by('-pk') if grant_stats.exists(): grant_amount = grant_stats.first().val / 1000 nav_options = [ { 'label': 'All', 'keyword': '' }, { 'label': 'Security', 'keyword': 'security' }, { 'label': 'Scalability', 'keyword': 'scalability' }, { 'label': 'UI/UX', 'keyword': 'UI' }, { 'label': 'DeFI', 'keyword': 'defi' }, { 'label': 'Education', 'keyword': 'education' }, { 'label': 'Wallets', 'keyword': 'wallet' }, { 'label': 'Community', 'keyword': 'community' }, { 'label': 'ETH 2.0', 'keyword': 'ETH 2.0' }, { 'label': 'ETH 1.x', 'keyword': 'ETH 1.x' }, ] now = datetime.datetime.now() params = { 'active': 'grants_landing', 'title': matching_live + str(_('Gitcoin Grants Explorer')), 'sort': sort, 'network': network, 'keyword': keyword, 'clr_matching_banners_style': clr_matching_banners_style, 'nav_options': nav_options, 'current_partners': partners.filter(end_date__gte=now).order_by('-amount'), 'past_partners': partners.filter(end_date__lt=now).order_by('-amount'), 'card_desc': _('Provide sustainable funding for Open Source with Gitcoin Grants'), 'card_player_override': 'https://www.youtube.com/embed/eVgEWSPFR2o', 'card_player_stream_override': static('v2/card/grants.mp4'), 'card_player_thumb_override': static('v2/card/grants.png'), 'grants': grants, 'grants_count': _grants.count(), 'keywords': get_keywords(), 'grant_amount': grant_amount, } # log this search, it might be useful for matching purposes down the line if keyword: try: SearchHistory.objects.update_or_create(search_type='grants', user=request.user, data=request.GET, ip_address=get_ip(request)) except Exception as e: logger.debug(e) pass return TemplateResponse(request, 'grants/index.html', params)
def preprocess(request): """Handle inserting pertinent data into the current context.""" # make lbcheck super lightweight if request.path == '/lbcheck': return {} from marketing.utils import get_stat try: num_slack = int(get_stat('slack_users')) except Exception: num_slack = 0 if num_slack > 1000: num_slack = f'{str(round((num_slack) / 1000, 1))}k' user_is_authenticated = request.user.is_authenticated profile = request.user.profile if user_is_authenticated and hasattr( request.user, 'profile') else None email_subs = profile.email_subscriptions if profile else None email_key = email_subs.first( ).priv if user_is_authenticated and email_subs and email_subs.exists( ) else '' if user_is_authenticated and profile and profile.pk: # what actions to take? record_join = not profile.last_visit record_visit = not profile.last_visit or profile.last_visit < ( timezone.now() - timezone.timedelta(seconds=RECORD_VISIT_EVERY_N_SECONDS)) if record_visit: ip_address = get_ip(request) profile.last_visit = timezone.now() try: profile.as_dict = json.loads(json.dumps(profile.to_dict())) profile.save() except Exception as e: logger.exception(e) metadata = { 'useragent': request.META['HTTP_USER_AGENT'], 'referrer': request.META.get('HTTP_REFERER', None), 'path': request.META.get('PATH_INFO', None), } UserAction.objects.create( user=request.user, profile=profile, action='Visit', location_data=get_location_from_ip(ip_address), ip_address=ip_address, utm=_get_utm_from_cookie(request), metadata=metadata, ) if record_join: Activity.objects.create(profile=profile, activity_type='joined') # handles marketing callbacks if request.GET.get('cb'): callback = request.GET.get('cb') handle_marketing_callback(callback, request) chat_unread_messages = False if profile and profile.chat_id: try: from chat.tasks import get_driver chat_driver = get_driver() chat_unreads_request = chat_driver.teams.get_team_unreads_for_user( profile.chat_id) if 'message' not in chat_unreads_request: for teams in chat_unreads_request: if teams['msg_count'] > 0 or teams['mention_count'] > 0: chat_unread_messages = True break except Exception as e: logger.error(str(e)) context = { 'STATIC_URL': settings.STATIC_URL, 'MEDIA_URL': settings.MEDIA_URL, 'num_slack': num_slack, 'chat_unread_messages': chat_unread_messages, 'github_handle': request.user.username if user_is_authenticated else False, 'email': request.user.email if user_is_authenticated else False, 'name': request.user.get_full_name() if user_is_authenticated else False, 'raven_js_version': settings.RAVEN_JS_VERSION, 'raven_js_dsn': settings.SENTRY_JS_DSN, 'release': settings.RELEASE, 'env': settings.ENV, 'INFURA_V3_PROJECT_ID': settings.INFURA_V3_PROJECT_ID, 'email_key': email_key, 'orgs': profile.organizations if profile else [], 'profile_id': profile.id if profile else '', 'hotjar': settings.HOTJAR_CONFIG, 'ipfs_config': { 'host': settings.JS_IPFS_HOST, 'port': settings.IPFS_API_PORT, 'protocol': settings.IPFS_API_SCHEME, 'root': settings.IPFS_API_ROOT, }, 'access_token': profile.access_token if profile else '', 'is_staff': request.user.is_staff if user_is_authenticated else False, 'is_moderator': profile.is_moderator if profile else False, 'persona_is_funder': profile.persona_is_funder if profile else False, 'persona_is_hunter': profile.persona_is_hunter if profile else False, 'profile_url': profile.url if profile else False, 'quests_live': settings.QUESTS_LIVE, } context['json_context'] = json.dumps(context) if context['github_handle']: context['unclaimed_tips'] = Tip.objects.filter( expires_date__gte=timezone.now(), receive_txid='', username__iexact=context['github_handle'], web3_type='v3', ).send_happy_path() context['unclaimed_kudos'] = KudosTransfer.objects.filter( receive_txid='', username__iexact="@" + context['github_handle'], web3_type='v3', ).send_happy_path() if not settings.DEBUG: context['unclaimed_tips'] = context['unclaimed_tips'].filter( network='mainnet') context['unclaimed_kudos'] = context['unclaimed_kudos'].filter( network='mainnet') return context
def grants(request): """Handle grants explorer.""" limit = request.GET.get('limit', 6) page = request.GET.get('page', 1) sort = request.GET.get('sort_option', 'weighted_shuffle') network = request.GET.get('network', 'mainnet') keyword = request.GET.get('keyword', '') grant_type = request.GET.get('type', 'tech') state = request.GET.get('state', 'active') _grants = None sort_by_index = None sort_by_clr_pledge_matching_amount = None if 'match_pledge_amount_' in sort: sort_by_clr_pledge_matching_amount = int(sort.split('amount_')[1]) sort_by = 'pk' if state == 'active': _grants = Grant.objects.filter( network=network, hidden=False, grant_type=grant_type).active().keyword(keyword).order_by(sort) else: _grants = Grant.objects.filter( network=network, hidden=False, grant_type=grant_type).keyword(keyword).order_by(sort) clr_prediction_curve_schema_map = {10**x: x + 1 for x in range(0, 5)} if sort_by_clr_pledge_matching_amount in clr_prediction_curve_schema_map.keys( ): sort_by_index = clr_prediction_curve_schema_map.get( sort_by_clr_pledge_matching_amount, 0) field_name = f'clr_prediction_curve__{sort_by_index}__2' _grants = _grants.order_by(f"-{field_name}") paginator = Paginator(_grants, limit) grants = paginator.get_page(page) partners = MatchPledge.objects.filter( active=True, pledge_type=grant_type) if grant_type else MatchPledge.objects.filter( active=True) now = datetime.datetime.now() current_partners = partners.filter(end_date__gte=now).order_by('-amount') past_partners = partners.filter(end_date__lt=now).order_by('-amount') current_partners_fund = 0 for partner in current_partners: current_partners_fund += partner.amount grant_amount = 0 grant_stats = Stat.objects.filter(key='grants', ).order_by('-pk') if grant_stats.exists(): grant_amount = grant_stats.first().val / 1000 tech_grants_count = Grant.objects.filter(network=network, hidden=False, grant_type='tech').count() media_grants_count = Grant.objects.filter(network=network, hidden=False, grant_type='media').count() nav_options = [ { 'label': 'All', 'keyword': '' }, { 'label': 'Security', 'keyword': 'security' }, { 'label': 'Scalability', 'keyword': 'scalability' }, { 'label': 'UI/UX', 'keyword': 'UI' }, { 'label': 'DeFI', 'keyword': 'defi' }, { 'label': 'Education', 'keyword': 'education' }, { 'label': 'Wallets', 'keyword': 'wallet' }, { 'label': 'Community', 'keyword': 'community' }, { 'label': 'ETH 2.0', 'keyword': 'ETH 2.0' }, { 'label': 'ETH 1.x', 'keyword': 'ETH 1.x' }, ] grant_types = [{ 'label': 'Tech', 'keyword': 'tech', 'count': tech_grants_count }, { 'label': 'Media', 'keyword': 'media', 'count': media_grants_count }] params = { 'active': 'grants_landing', 'title': matching_live + str(_('Gitcoin Grants Explorer')), 'sort': sort, 'network': network, 'keyword': keyword, 'type': grant_type, 'clr_matching_banners_style': clr_matching_banners_style, 'nav_options': nav_options, 'grant_types': grant_types, 'current_partners_fund': current_partners_fund, 'current_partners': current_partners, 'past_partners': past_partners, 'card_desc': _('Provide sustainable funding for Open Source with Gitcoin Grants'), 'card_player_override': 'https://www.youtube.com/embed/eVgEWSPFR2o', 'card_player_stream_override': static('v2/card/grants.mp4'), 'card_player_thumb_override': static('v2/card/grants.png'), 'grants': grants, 'keywords': get_keywords(), 'grant_amount': grant_amount, 'total_clr_pot': total_clr_pot, 'clr_active': clr_active, 'sort_by_index': sort_by_index, 'clr_round': clr_round, 'show_past_clr': show_past_clr, 'is_staff': request.user.is_staff } # log this search, it might be useful for matching purposes down the line if keyword: try: SearchHistory.objects.update_or_create(search_type='grants', user=request.user, data=request.GET, ip_address=get_ip(request)) except Exception as e: logger.debug(e) pass return TemplateResponse(request, 'grants/index.html', params)
def send_tip_4(request): """Handle the fourth stage of sending a tip (the POST). Returns: JsonResponse: response with success state. """ response = { 'status': 'OK', 'message': _('Tip Sent'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' params = json.loads(request.body) txid = params['txid'] destinationAccount = params['destinationAccount'] is_direct_to_recipient = params.get('is_direct_to_recipient', False) if is_direct_to_recipient: tip = Tip.objects.get( metadata__direct_address=destinationAccount, metadata__creation_time=params['creation_time'], metadata__salt=params['salt'], ) else: tip = Tip.objects.get( metadata__address=destinationAccount, metadata__salt=params['salt'], ) is_authenticated_for_this_via_login = (tip.from_username and tip.from_username == from_username) is_authenticated_for_this_via_ip = tip.ip == get_ip(request) is_authed = is_authenticated_for_this_via_ip or is_authenticated_for_this_via_login if not is_authed: response = { 'status': 'error', 'message': _('Permission Denied'), } return JsonResponse(response) # db mutations tip.txid = txid tip.tx_status = 'pending' if is_direct_to_recipient: tip.receive_txid = txid tip.receive_tx_status = 'pending' tip.receive_address = destinationAccount TipPayout.objects.create( txid=txid, profile=get_profile(tip.username), tip=tip, ) tip.save() from townsquare.tasks import calculate_clr_match calculate_clr_match.delay() # notifications maybe_market_tip_to_github(tip) maybe_market_tip_to_slack(tip, 'New tip') if tip.primary_email: maybe_market_tip_to_email(tip, [tip.primary_email]) record_user_action(tip.from_username, 'send_tip', tip) record_tip_activity(tip, tip.from_username, 'new_tip' if tip.username else 'new_crowdfund', False, tip.username) return JsonResponse(response)
def preprocess(request): """Handle inserting pertinent data into the current context.""" # make lbcheck super lightweight if request.path == '/lbcheck': return {} from marketing.utils import get_stat try: num_slack = int(get_stat('slack_users')) except Exception: num_slack = 0 if num_slack > 1000: num_slack = f'{str(round((num_slack) / 1000, 1))}k' user_is_authenticated = request.user.is_authenticated profile = request.user.profile if user_is_authenticated and hasattr(request.user, 'profile') else None email_subs = profile.email_subscriptions if profile else None email_key = email_subs.first().priv if user_is_authenticated and email_subs and email_subs.exists() else '' if user_is_authenticated and profile and profile.pk: record_visit = not profile.last_visit or profile.last_visit < ( timezone.now() - timezone.timedelta(seconds=RECORD_VISIT_EVERY_N_SECONDS) ) if record_visit: ip_address = get_ip(request) profile.last_visit = timezone.now() profile.save() UserAction.objects.create( user=request.user, profile=profile, action='Visit', location_data=get_location_from_ip(ip_address), ip_address=ip_address, utm=_get_utm_from_cookie(request), ) context = { 'STATIC_URL': settings.STATIC_URL, 'MEDIA_URL': settings.MEDIA_URL, 'num_slack': num_slack, 'github_handle': request.user.username if user_is_authenticated else False, 'email': request.user.email if user_is_authenticated else False, 'name': request.user.get_full_name() if user_is_authenticated else False, 'sentry_address': settings.SENTRY_ADDRESS, 'raven_js_version': settings.RAVEN_JS_VERSION, 'raven_js_dsn': settings.SENTRY_JS_DSN, 'release': settings.RELEASE, 'env': settings.ENV, 'email_key': email_key, 'profile_id': profile.id if profile else '', 'hotjar': settings.HOTJAR_CONFIG, 'ipfs_config': { 'host': settings.JS_IPFS_HOST, 'port': settings.IPFS_API_PORT, 'protocol': settings.IPFS_API_SCHEME, 'root': settings.IPFS_API_ROOT, }, 'access_token': profile.access_token if profile else '', 'is_staff': request.user.is_staff if user_is_authenticated else False, 'is_moderator': profile.is_moderator if profile else False, } context['json_context'] = json.dumps(context) if context['github_handle']: context['unclaimed_tips'] = Tip.objects.filter( expires_date__gte=timezone.now(), receive_txid='', username__iexact=context['github_handle'], web3_type='v3', ).send_happy_path() context['unclaimed_kudos'] = KudosTransfer.objects.filter( receive_txid='', username__iexact="@" + context['github_handle'], web3_type='v3', ).send_happy_path() if not settings.DEBUG: context['unclaimed_tips'] = context['unclaimed_tips'].filter(network='mainnet') context['unclaimed_kudos'] = context['unclaimed_kudos'].filter(network='mainnet') return context
def receive_bulk(request, secret): coupons = BulkTransferCoupon.objects.filter(secret=secret) if not coupons.exists(): raise Http404 coupon = coupons.first() _class = request.GET.get('class', '') if coupon.num_uses_remaining <= 0: messages.info(request, f'Sorry but the coupon for a free kudos has has expired. Contact the person who sent you the coupon link, or you can still purchase one on this page.') return redirect(coupon.token.url) kudos_transfer = None if request.user.is_authenticated: redemptions = BulkTransferRedemption.objects.filter(redeemed_by=request.user.profile, coupon=coupon) if redemptions.exists(): kudos_transfer = redemptions.first().kudostransfer error = False if request.POST: try: address = Web3.toChecksumAddress(request.POST.get('forwarding_address')) except: error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again." if request.user.is_anonymous: error = "You must login." if not error: user = request.user profile = user.profile save_addr = request.POST.get('save_addr') ip_address = get_ip(request) # handle form submission if save_addr: profile.preferred_payout_address = address profile.save() kudos_contract_address = Web3.toChecksumAddress(settings.KUDOS_CONTRACT_MAINNET) kudos_owner_address = Web3.toChecksumAddress(settings.KUDOS_OWNER_ACCOUNT) w3 = get_web3(coupon.token.contract.network) contract = w3.eth.contract(Web3.toChecksumAddress(kudos_contract_address), abi=kudos_abi()) nonce = w3.eth.getTransactionCount(kudos_owner_address) tx = contract.functions.clone(address, coupon.token.token_id, 1).buildTransaction({ 'nonce': nonce, 'gas': 500000, 'gasPrice': int(recommend_min_gas_price_to_confirm_in_time(2) * 10**9), 'value': int(coupon.token.price_finney / 1000.0 * 10**18), }) if not profile.trust_profile and profile.github_created_on > (timezone.now() - timezone.timedelta(days=7)): messages.error(request, f'Your github profile is too new. Cannot receive kudos.') else: signed = w3.eth.account.signTransaction(tx, settings.KUDOS_PRIVATE_KEY) try: txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex() with transaction.atomic(): kudos_transfer = KudosTransfer.objects.create( emails=[request.user.email], # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=coupon.token, amount=coupon.token.price_in_eth, comments_public=coupon.comments_to_put_in_kudos_transfer, ip=ip_address, github_url='', from_name=coupon.sender_profile.handle, from_email='', from_username=coupon.sender_profile.handle, username=profile.handle, network=coupon.token.contract.network, from_address=settings.KUDOS_OWNER_ACCOUNT, is_for_bounty_fulfiller=False, metadata={'coupon_redemption': True, 'nonce': nonce}, recipient_profile=profile, sender_profile=coupon.sender_profile, txid=txid, receive_txid=txid, tx_status='pending', receive_tx_status='pending', ) # save to DB BulkTransferRedemption.objects.create( coupon=coupon, redeemed_by=profile, ip_address=ip_address, kudostransfer=kudos_transfer, ) coupon.num_uses_remaining -= 1 coupon.current_uses += 1 coupon.save() # send email maybe_market_kudos_to_email(kudos_transfer) except: error = "Could not redeem your kudos. Please try again soon." title = f"Redeem {coupon.token.humanized_name} Kudos from @{coupon.sender_profile.handle}" desc = f"This Kudos has been AirDropped to you. About this Kudos: {coupon.token.description}" params = { 'title': title, 'card_title': title, 'card_desc': desc, 'error': error, 'avatar_url': coupon.token.img_url, 'coupon': coupon, 'user': request.user, 'is_authed': request.user.is_authenticated, 'kudos_transfer': kudos_transfer, 'tweet_text': urllib.parse.quote_plus(f"I just got a {coupon.token.humanized_name} Kudos on @gitcoin. ") } return TemplateResponse(request, 'transaction/receive_bulk.html', params)
def whitepaper_access(request, ratelimited=False): context = { 'active': 'whitepaper', 'title': 'Whitepaper', 'minihero': 'Whitepaper', 'suppress_logo': True, } if not request.POST.get('submit', False): return TemplateResponse(request, 'whitepaper_accesscode.html', context) if ratelimited: context[ 'msg'] = "You're ratelimited. Please contact [email protected]" return TemplateResponse(request, 'whitepaper_accesscode.html', context) context['accesskey'] = request.POST.get('accesskey') context['email'] = request.POST.get('email') access_codes = AccessCodes.objects.filter( invitecode=request.POST.get('accesskey')) valid_access_code = access_codes.exists() if not valid_access_code: context[ 'msg'] = "Invalid Access Code. Please contact [email protected]" return TemplateResponse(request, 'whitepaper_accesscode.html', context) ac = access_codes.first() if ac.uses >= ac.maxuses: context[ 'msg'] = "You have exceeded your maximum number of uses for this access code. Please contact [email protected]" return TemplateResponse(request, 'whitepaper_accesscode.html', context) valid_email = True try: validate_email(request.POST.get('email', False)) except Exception as e: valid_email = False if not request.POST.get('email', False) or not valid_email: context['msg'] = "Invalid Email. Please contact [email protected]" return TemplateResponse(request, 'whitepaper_accesscode.html', context) ip = get_ip(request) wa = WhitepaperAccess.objects.create( invitecode=request.POST.get('accesskey', False), email=request.POST.get('email', False), ip=ip, ) send_mail(settings.CONTACT_EMAIL, settings.CONTACT_EMAIL, "New Whitepaper Generated", str(wa)) # bottom watermark packet1 = StringIO.StringIO() can = canvas.Canvas(packet1, pagesize=letter) grey = Color(22 / 255, 6 / 255, 62 / 255, alpha=0.3) can.setFillColor(grey) can.setFontSize(8) lim = 30 email__etc = wa.email if len(wa.email) < lim else wa.email[0:lim] + "..." msg = "Generated for access code {} by email {} at {} via ip: {}. https://gitcoin.co/whitepaper".format( wa.invitecode, email__etc, wa.created_on.strftime("%Y-%m-%d %H:%M"), wa.ip) charlength = 3.5 width = len(msg) * charlength left = (600 - width) / 2 can.drawString(left, 7, msg) can.save() # middle watermark packet2 = StringIO.StringIO() can = canvas.Canvas(packet2, pagesize=letter) grey = Color(22 / 255, 6 / 255, 62 / 255, alpha=0.02) can.setFillColor(grey) can.setFontSize(100) msg = "WP{}".format(str(wa.pk).zfill(5)) charlength = 55 width = len(msg) * charlength left = (600 - width) / 2 can.rotate(45) can.drawString(320, 50, msg) can.save() #move to the beginning of the StringIO buffer file_name = 'whitepaper.pdf' path_to_file = 'assets/other/wp.pdf' new_pdf1 = PdfFileReader(packet1) new_pdf2 = PdfFileReader(packet2) # read your existing PDF existing_pdf = PdfFileReader(file(path_to_file, "rb")) output = PdfFileWriter() # add the "watermark" (which is the new pdf) on the existing page try: for i in range(0, 50): page = existing_pdf.getPage(i) page.mergePage(new_pdf1.getPage(0)) if i != 0: page.mergePage(new_pdf2.getPage(0)) output.addPage(page) except Exception as e: print(e) # finally, write "output" to a real file outputfile = "output/whitepaper_{}.pdf".format(wa.pk) outputStream = file(outputfile, "wb") output.write(outputStream) outputStream.close() filename = outputfile wrapper = FileWrapper(file(filename)) response = HttpResponse(wrapper, content_type='application/pdf') response['Content-Length'] = os.path.getsize(filename) return response
def send_3(request): """Handle the third stage of sending a kudos (the POST). This function is derived from send_tip_3. The request to send the kudos is added to the database, but the transaction has not happened yet. The txid is added in `send_kudos_4`. Returns: JsonResponse: The response with success state. """ response = { 'status': 'OK', 'message': _('Kudos Created'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' primary_from_email = request.user.email if is_user_authenticated else '' access_token = request.user.profile.get_access_token() if is_user_authenticated and request.user.profile else '' to_emails = [] params = json.loads(request.body) to_username = params.get('username', '').lstrip('@') to_emails = get_emails_master(to_username) email = params.get('email') if email: to_emails.append(email) # If no primary email in session, try the POST data. If none, fetch from GH. primary_from_email = params.get('fromEmail') if access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) to_emails = list(set(to_emails)) # Validate that the token exists on the back-end kudos_id = params.get('kudosId') if not kudos_id: raise Http404 try: kudos_token_cloned_from = Token.objects.get(pk=kudos_id) except Token.DoesNotExist: raise Http404 # db mutations KudosTransfer.objects.create( emails=to_emails, # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=kudos_token_cloned_from, amount=params['amount'], comments_public=params['comments_public'], ip=get_ip(request), github_url=params['github_url'], from_name=params['from_name'], from_email=params['from_email'], from_username=from_username, username=params['username'], network=params['network'], tokenAddress=params['tokenAddress'], from_address=params['from_address'], is_for_bounty_fulfiller=params['is_for_bounty_fulfiller'], metadata=params['metadata'], recipient_profile=get_profile(to_username), sender_profile=get_profile(from_username), ) return JsonResponse(response)
def send_tip_3(request): """Handle the third stage of sending a tip (the POST). Returns: JsonResponse: response with success state. """ response = { 'status': 'OK', 'message': _('Tip Created'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' primary_from_email = request.user.email if is_user_authenticated else '' access_token = request.user.profile.get_access_token( ) if is_user_authenticated and request.user.profile else '' params = json.loads(request.body) to_username = params['username'].lstrip('@') to_emails = get_emails_by_category(to_username) primary_email = '' if params.get('email'): primary_email = params['email'] elif to_emails.get('primary', None): primary_email = to_emails['primary'] elif to_emails.get('github_profile', None): primary_email = to_emails['github_profile'] else: if len(to_emails.get('events', None)): primary_email = to_emails['events'][0] else: print( "TODO: no email found. in the future, we should handle this case better because it's GOING to end up as a support request" ) if primary_email and isinstance(primary_email, list): primary_email = primary_email[0] # If no primary email in session, try the POST data. If none, fetch from GH. if params.get('fromEmail'): primary_from_email = params['fromEmail'] elif access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) expires_date = timezone.now() + timezone.timedelta( seconds=params['expires_date']) # metadata metadata = params['metadata'] metadata['user_agent'] = request.META.get('HTTP_USER_AGENT', '') # db mutations tip = Tip.objects.create( primary_email=primary_email, emails=to_emails, tokenName=params['tokenName'], amount=params['amount'], comments_priv=params['comments_priv'], comments_public=params['comments_public'], ip=get_ip(request), expires_date=expires_date, github_url=params['github_url'], from_name=params['from_name'] if params['from_name'] != 'False' else '', from_email=params['from_email'], from_username=from_username, username=params['username'], network=params['network'], tokenAddress=params['tokenAddress'], from_address=params['from_address'], is_for_bounty_fulfiller=params['is_for_bounty_fulfiller'], metadata=metadata, recipient_profile=get_profile(to_username), sender_profile=get_profile(from_username), ) is_over_tip_tx_limit = False is_over_tip_weekly_limit = False max_per_tip = request.user.profile.max_tip_amount_usdt_per_tx if request.user.is_authenticated and request.user.profile else 500 if tip.value_in_usdt_now: is_over_tip_tx_limit = tip.value_in_usdt_now > max_per_tip if request.user.is_authenticated and request.user.profile: tips_last_week_value = tip.value_in_usdt_now tips_last_week = Tip.objects.send_happy_path().filter( sender_profile=get_profile(from_username), created_on__gt=timezone.now() - timezone.timedelta(days=7)) for this_tip in tips_last_week: if this_tip.value_in_usdt_now: tips_last_week_value += this_tip.value_in_usdt_now is_over_tip_weekly_limit = tips_last_week_value > request.user.profile.max_tip_amount_usdt_per_week increase_funding_form_title = _('Request a Funding Limit Increasement') increase_funding_form = f'<a target="_blank" href="{settings.BASE_URL}'\ f'requestincrease">{increase_funding_form_title}</a>' if is_over_tip_tx_limit: response['status'] = 'error' response['message'] = _('This tip is over the per-transaction limit of $') +\ str(max_per_tip) + '. ' + increase_funding_form elif is_over_tip_weekly_limit: response['status'] = 'error' response['message'] = _('You are over the weekly tip send limit of $') +\ str(request.user.profile.max_tip_amount_usdt_per_week) +\ '. ' + increase_funding_form return JsonResponse(response)
def redeem_coin(request, shortcode): if request.body: status = 'OK' body_unicode = request.body.decode('utf-8') body = json.loads(body_unicode) address = body['address'] try: coin = CoinRedemption.objects.get(shortcode=shortcode) address = Web3.toChecksumAddress(address) if hasattr(coin, 'coinredemptionrequest'): status = 'error' message = 'Bad request' else: abi = json.loads( '[{"constant":true,"inputs":[],"name":"mintingFinished","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"MintFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]' ) # Instantiate Colorado Coin contract contract = w3.eth.contract(coin.contract_address, abi=abi) tx = contract.functions.transfer( address, coin.amount * 10**18).buildTransaction({ 'nonce': w3.eth.getTransactionCount( settings.COLO_ACCOUNT_ADDRESS), 'gas': 100000, 'gasPrice': recommend_min_gas_price_to_confirm_in_time(5) * 10**9 }) signed = w3.eth.account.signTransaction( tx, settings.COLO_ACCOUNT_PRIVATE_KEY) transaction_id = w3.eth.sendRawTransaction( signed.rawTransaction).hex() CoinRedemptionRequest.objects.create(coin_redemption=coin, ip=get_ip(request), sent_on=timezone.now(), txid=transaction_id, txaddress=address) message = transaction_id except CoinRedemption.DoesNotExist: status = 'error' message = 'Bad request' except Exception as e: status = 'error' message = str(e) # http response response = { 'status': status, 'message': message, } return JsonResponse(response) try: coin = CoinRedemption.objects.get(shortcode=shortcode) params = { 'class': 'redeem', 'title': 'Coin Redemption', 'coin_status': 'PENDING' } try: coin_redeem_request = CoinRedemptionRequest.objects.get( coin_redemption=coin) params['colo_txid'] = coin_redeem_request.txid except CoinRedemptionRequest.DoesNotExist: params['coin_status'] = 'INITIAL' return TemplateResponse(request, 'yge/redeem_coin.html', params) except CoinRedemption.DoesNotExist: raise Http404
def email_settings(request, key): """Display email settings. Args: key (str): The private key to lookup email subscriber data. TODO: * Remove all ES.priv_key lookups and use request.user only. * Remove settings_helper_get_auth usage. Returns: TemplateResponse: The email settings view populated with ES data. """ profile, es, __, __ = settings_helper_get_auth(request, key) if not request.user.is_authenticated and (not es and key) or ( request.user.is_authenticated and not hasattr(request.user, 'profile')): return redirect('/login/github/?next=' + request.get_full_path()) # handle 'noinput' case email = '' level = '' msg = '' email_types = {} from retail.emails import ALL_EMAILS for em in ALL_EMAILS: email_types[em[0]] = str(em[1]) email_type = request.GET.get('type') if email_type in email_types: email = es.email if es: key = get_or_save_email_subscriber(email, 'settings') es.email = email unsubscribed_email_type = {} unsubscribed_email_type[email_type] = True if email_type == 'marketing': set_mautic_dnc(profile, es, unsubscribed_email_type) es.build_email_preferences(unsubscribed_email_type) es = record_form_submission(request, es, 'email') ip = get_ip(request) if not es.metadata.get('ip', False): es.metadata['ip'] = [ip] else: es.metadata['ip'].append(ip) es.save() context = { 'title': _('Email unsubscription successful'), 'type': email_types[email_type] } return TemplateResponse(request, 'email_unsubscribed.html', context) if request.POST and request.POST.get('submit'): email = request.POST.get('email') level = request.POST.get('level') validation_passed = True try: email_in_use = User.objects.filter( email=email) | User.objects.filter(profile__email=email) email_used_marketing = EmailSubscriber.objects.filter( email=email).select_related('profile') logged_in = request.user.is_authenticated email_already_used = (email_in_use or email_used_marketing) user = request.user if logged_in else None email_used_by_me = (user and (user.email == email or user.profile.email == email)) email_changed = es.email != email if email_changed and email_already_used and not email_used_by_me: raise ValueError( f'{request.user} attempting to use an email which is already in use on the platform' ) validate_email(email) except Exception as e: print(e) validation_passed = False msg = str(e) if validation_passed: if es: key = get_or_save_email_subscriber(email, 'settings') es.preferences['level'] = level es.email = email form = dict(request.POST) # form was not sending falses, so default them if not there for email_tuple in ALL_EMAILS: key = email_tuple[0] if key not in form.keys(): form[key] = False set_mautic_dnc(profile, es, form) es.build_email_preferences(form) es = record_form_submission(request, es, 'email') ip = get_ip(request) es.active = level != 'nothing' es.newsletter = level in ['regular', 'lite1'] if not es.metadata.get('ip', False): es.metadata['ip'] = [ip] else: es.metadata['ip'].append(ip) es.save() msg = _('Updated your preferences.') pref_lang = 'en' if not profile else profile.get_profile_preferred_language( ) context = { 'nav': 'home', 'active': '/settings/email/', 'title': _('Email Settings'), 'es': es, 'nav': 'home', 'suppression_preferences': json.dumps( es.preferences.get('suppression_preferences', {}) if es else {}), 'msg': msg, 'profile': request.user.profile if request.user.is_authenticated else None, 'email_types': ALL_EMAILS, 'navs': get_settings_navs(request), 'preferred_language': pref_lang } return TemplateResponse(request, 'settings/email.html', context)
def get_queryset(self): """Get the queryset for Bounty. Returns: QuerySet: The Bounty queryset. """ param_keys = self.request.query_params.keys() queryset = Bounty.objects.prefetch_related('fulfillments', 'interested', 'interested__profile', 'activities') if 'not_current' not in param_keys: queryset = queryset.current() queryset = queryset.order_by('-web3_created') # filtering for key in [ 'raw_data', 'experience_level', 'project_length', 'bounty_type', 'bounty_owner_address', 'idx_status', 'network', 'bounty_owner_github_username', 'standard_bounties_id', 'permission_type', 'project_type' ]: if key in param_keys: # special hack just for looking up bounties posted by a certain person request_key = key if key != 'bounty_owner_address' else 'coinbase' val = self.request.query_params.get(request_key, '') values = val.strip().split(',') values = [value for value in values if value and val.strip()] if values: _queryset = queryset.none() for value in values: args = {} args[f'{key}__icontains'] = value.strip() _queryset = _queryset | queryset.filter(**args) queryset = _queryset # filter by PK if 'pk__gt' in param_keys: queryset = queryset.filter( pk__gt=self.request.query_params.get('pk__gt')) # Filter by a list of PKs if 'pk__in' in param_keys: try: list_of_pks = self.request.query_params.get('pk__in').split( ',') queryset = queryset.filter(pk__in=list_of_pks) except Exception: pass # filter by standard_bounties_id if 'standard_bounties_id__in' in param_keys: statuses = self.request.query_params.get( 'standard_bounties_id__in').split(',') queryset = queryset.filter(standard_bounties_id__in=statuses) # filter by statuses if 'status__in' in param_keys: statuses = self.request.query_params.get('status__in').split(',') queryset = queryset.filter(idx_status__in=statuses) # filter by who is interested if 'started' in param_keys: queryset = queryset.filter(interested__profile__handle__in=[ self.request.query_params.get('started') ]) # filter by is open or not if 'is_open' in param_keys: queryset = queryset.filter(is_open=self.request.query_params.get( 'is_open', '').lower() == 'true') queryset = queryset.filter(expires_date__gt=datetime.now()) # filter by urls if 'github_url' in param_keys: urls = self.request.query_params.get('github_url').split(',') queryset = queryset.filter(github_url__in=urls) # filter by orgs if 'org' in param_keys: val = self.request.query_params.get('org', '') values = val.strip().split(',') values = [value for value in values if value and val.strip()] if values: _queryset = queryset.none() for value in values: org = value.strip() _queryset = _queryset | queryset.filter( github_url__icontains=f'https://github.com/{org}') queryset = _queryset # Retrieve all fullfilled bounties by fulfiller_username if 'fulfiller_github_username' in param_keys: queryset = queryset.filter( fulfillments__fulfiller_github_username__iexact=self.request. query_params.get('fulfiller_github_username')) # Retrieve all DONE fullfilled bounties by fulfiller_username if 'fulfiller_github_username_done' in param_keys: queryset = queryset.filter( fulfillments__fulfiller_github_username__iexact=self.request. query_params.get('fulfiller_github_username'), fulfillments__accepted=True, ) # Retrieve all interested bounties by profile handle if 'interested_github_username' in param_keys: queryset = queryset.filter( interested__profile__handle__iexact=self.request.query_params. get('interested_github_username')) # Retrieve all mod bounties. # TODO: Should we restrict this to staff only..? Technically I don't think we're worried about that atm? if 'moderation_filter' in param_keys: mod_filter = self.request.query_params.get('moderation_filter') if mod_filter == 'needs_review': queryset = queryset.needs_review() elif mod_filter == 'warned': queryset = queryset.warned() elif mod_filter == 'escalated': queryset = queryset.escalated() elif mod_filter == 'closed_on_github': queryset = queryset.closed() elif mod_filter == 'hidden': queryset = queryset.hidden() elif mod_filter == 'not_started': queryset = queryset.not_started() # All Misc Api things if 'misc' in param_keys: if self.request.query_params.get('misc') == 'hiring': queryset = queryset.exclude( attached_job_description__isnull=True).exclude( attached_job_description='') if 'keyword' in param_keys: queryset = queryset.keyword( self.request.query_params.get('keyword')) if 'is_featured' in param_keys: queryset = queryset.filter( is_featured=self.request.query_params.get('is_featured'), is_open=True, ) # order order_by = self.request.query_params.get('order_by') if order_by and order_by != 'null': queryset = queryset.order_by(order_by) queryset = queryset.distinct() # offset / limit if 'is_featured' not in param_keys: limit = int(self.request.query_params.get('limit', 5)) max_bounties = 100 if limit > max_bounties: limit = max_bounties offset = self.request.query_params.get('offset', 0) if limit: start = int(offset) end = start + int(limit) queryset = queryset[start:end] data = dict(self.request.query_params) data.pop('is_featured', None) # save search history, but only not is_featured if 'is_featured' not in param_keys: if self.request.user and self.request.user.is_authenticated: data['nonce'] = int(time.time() / 1000) SearchHistory.objects.update_or_create(user=self.request.user, data=data, ip_address=get_ip( self.request)) return queryset
def account_settings(request): """Display and save user's Account settings. Returns: TemplateResponse: The user's Account settings template response. """ msg = '' profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not profile or not is_logged_in: login_redirect = redirect('/login/github/?next=' + request.get_full_path()) return login_redirect if request.POST: if 'persona_is_funder' or 'persona_is_hunter' in request.POST.keys(): profile.persona_is_funder = bool( request.POST.get('persona_is_funder', False)) profile.persona_is_hunter = bool( request.POST.get('persona_is_hunter', False)) profile.save() if 'preferred_payout_address' in request.POST.keys(): eth_address = request.POST.get('preferred_payout_address', '') if not is_valid_eth_address(eth_address): eth_address = profile.preferred_payout_address profile.preferred_payout_address = eth_address profile.save() msg = _('Updated your Address') elif request.POST.get('export', False): export_type = request.POST.get('export_type', False) profile = request.user.profile earnings = profile.earnings if export_type == 'earnings' else profile.sent_earnings earnings = earnings.filter( network='mainnet').order_by('-created_on') return export_earnings_csv(earnings, export_type) elif request.POST.get('disconnect', False): profile.github_access_token = '' profile = record_form_submission(request, profile, 'account-disconnect') profile.email = '' profile.save() create_user_action(profile.user, 'account_disconnected', request) redirect_url = f'https://www.github.com/settings/connections/applications/{settings.GITHUB_CLIENT_ID}' logout(request) logout_redirect = redirect(redirect_url) logout_redirect[ 'Cache-Control'] = 'max-age=0 no-cache no-store must-revalidate' return logout_redirect elif request.POST.get('delete', False): # remove profile profile.hide_profile = True profile = record_form_submission(request, profile, 'account-delete') profile.email = '' profile.save() # remove email mautic_proxy_backend('POST', f'contacts/{profile.mautic_id}/delete') if es: es.delete() request.user.delete() AccountDeletionRequest.objects.create( handle=profile.handle.lower(), profile={ 'ip': get_ip(request), }) profile.avatar_baseavatar_related.all().delete() try: profile.delete() except: profile.github_access_token = '' profile.user = None profile.hide_profile = True profile.save() messages.success(request, _('Your account has been deleted.')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect else: msg = _('Error: did not understand your request') context = { 'is_logged_in': is_logged_in, 'nav': 'home', 'active': '/settings/account', 'title': _('Account Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': msg, } return TemplateResponse(request, 'settings/account.html', context)
def preprocess(request): """Handle inserting pertinent data into the current context.""" # make lbcheck super lightweight if request.path == '/lbcheck': return {} chat_url = get_chat_url(front_end=True) chat_access_token = '' chat_id = '' user_is_authenticated = request.user.is_authenticated profile = request.user.profile if user_is_authenticated and hasattr( request.user, 'profile') else None if user_is_authenticated and profile and profile.pk: # what actions to take? record_join = not profile.last_visit record_visit = not profile.last_visit or profile.last_visit < ( timezone.now() - timezone.timedelta(seconds=RECORD_VISIT_EVERY_N_SECONDS)) if record_visit: try: profile.last_visit = timezone.now() profile.save() except Exception as e: logger.exception(e) try: from dashboard.tasks import profile_dict profile_dict.delay(profile.pk) except Exception as e: logger.exception(e) metadata = { 'useragent': request.META['HTTP_USER_AGENT'], 'referrer': request.META.get('HTTP_REFERER', None), 'path': request.META.get('PATH_INFO', None), } ip_address = get_ip(request) UserAction.objects.create( user=request.user, profile=profile, action='Visit', location_data=get_location_from_ip(ip_address), ip_address=ip_address, utm=_get_utm_from_cookie(request), metadata=metadata, ) if record_join: Activity.objects.create(profile=profile, activity_type='joined') chat_access_token = profile.gitcoin_chat_access_token chat_id = profile.chat_id # handles marketing callbacks if request.GET.get('cb'): callback = request.GET.get('cb') handle_marketing_callback(callback, request) header_msg, footer_msg, nav_salt = get_sitewide_announcements() context = { 'STATIC_URL': settings.STATIC_URL, 'MEDIA_URL': settings.MEDIA_URL, 'chat_url': chat_url, 'chat_id': chat_id, 'chat_access_token': chat_access_token, 'github_handle': request.user.username.lower() if user_is_authenticated else False, 'email': request.user.email if user_is_authenticated else False, 'name': request.user.get_full_name() if user_is_authenticated else False, 'last_chat_status': request.user.profile.last_chat_status if (hasattr(request.user, 'profile') and user_is_authenticated) else False, 'raven_js_version': settings.RAVEN_JS_VERSION, 'raven_js_dsn': settings.SENTRY_JS_DSN, 'release': settings.RELEASE, 'env': settings.ENV, 'header_msg': header_msg, 'nav_salt': nav_salt, 'footer_msg': footer_msg, 'INFURA_V3_PROJECT_ID': settings.INFURA_V3_PROJECT_ID, 'giphy_key': settings.GIPHY_KEY, 'youtube_key': settings.YOUTUBE_API_KEY, 'orgs': profile.organizations if profile else [], 'profile_id': profile.id if profile else '', 'hotjar': settings.HOTJAR_CONFIG, 'ipfs_config': { 'host': settings.JS_IPFS_HOST, 'port': settings.IPFS_API_PORT, 'protocol': settings.IPFS_API_SCHEME, 'root': settings.IPFS_API_ROOT, }, 'chat_persistence_frequency': 90 * 1000, 'access_token': profile.access_token if profile else '', 'is_staff': request.user.is_staff if user_is_authenticated else False, 'is_moderator': profile.is_moderator if profile else False, 'is_alpha_tester': profile.is_alpha_tester if profile else False, 'persona_is_funder': profile.persona_is_funder if profile else False, 'persona_is_hunter': profile.persona_is_hunter if profile else False, 'profile_url': profile.url if profile else False, 'quests_live': settings.QUESTS_LIVE, } context['json_context'] = json.dumps(context) context['last_posts'] = cache.get_or_set('last_posts', fetchPost, 5000) if context['github_handle']: context['unclaimed_tips'] = Tip.objects.filter( receive_txid='', username__iexact=context['github_handle'], web3_type='v3', ).send_happy_path().cache(timeout=60) context['unclaimed_kudos'] = KudosTransfer.objects.filter( receive_txid='', username__iexact="@" + context['github_handle'], web3_type='v3', ).send_happy_path().cache(timeout=60) if not settings.DEBUG: context['unclaimed_tips'] = context['unclaimed_tips'].filter( network='mainnet').cache(timeout=60) context['unclaimed_kudos'] = context['unclaimed_kudos'].filter( network='mainnet').cache(timeout=60) return context
def job_settings(request): """Display and save user's Account settings. Returns: TemplateResponse: The user's Account settings template response. """ msg = '' profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not profile or not is_logged_in: login_redirect = redirect('/login/github/?next=' + request.get_full_path()) return login_redirect if request.POST: if 'preferred_payout_address' in request.POST.keys(): eth_address = request.POST.get('preferred_payout_address', '') if not is_valid_eth_address(eth_address): eth_address = profile.preferred_payout_address profile.preferred_payout_address = eth_address profile.save() msg = _('Updated your Address') elif request.POST.get('disconnect', False): profile.github_access_token = '' profile = record_form_submission(request, profile, 'account-disconnect') profile.email = '' profile.save() create_user_action(profile.user, 'account_disconnected', request) messages.success( request, _('Your account has been disconnected from Github')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect elif request.POST.get('delete', False): # remove profile profile.hide_profile = True profile = record_form_submission(request, profile, 'account-delete') profile.email = '' profile.save() # remove email mautic_proxy_backend('POST', f'contacts/{profile.mautic_id}/delete') if es: es.delete() request.user.delete() AccountDeletionRequest.objects.create( handle=profile.handle.lower(), profile={ 'ip': get_ip(request), }) profile.delete() messages.success(request, _('Your account has been deleted.')) logout_redirect = redirect(reverse('logout') + '?next=/') return logout_redirect else: msg = _('Error: did not understand your request') context = { 'is_logged_in': is_logged_in, 'nav': 'home', 'active': '/settings/job', 'title': _('Job Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': msg, } return TemplateResponse(request, 'settings/job.html', context)
def email_settings(request, key): """Display email settings. Args: key (str): The private key to lookup email subscriber data. TODO: * Remove all ES.priv_key lookups and use request.user only. * Remove settings_helper_get_auth usage. Returns: TemplateResponse: The email settings view populated with ES data. """ profile, es, user, is_logged_in = settings_helper_get_auth(request, key) if not request.user.is_authenticated and (not es and key) or ( request.user.is_authenticated and not hasattr(request.user, 'profile')): return redirect('/login/github?next=' + request.get_full_path()) # handle 'noinput' case email = '' level = '' msg = '' if request.POST and request.POST.get('submit'): email = request.POST.get('email') level = request.POST.get('level') preferred_language = request.POST.get('preferred_language') validation_passed = True try: validate_email(email) except Exception as e: print(e) validation_passed = False msg = _('Invalid Email') if preferred_language: if preferred_language not in [i[0] for i in settings.LANGUAGES]: msg = _('Unknown language') validation_passed = False if validation_passed: if profile: profile.pref_lang_code = preferred_language profile.save() request.session[LANGUAGE_SESSION_KEY] = preferred_language translation.activate(preferred_language) if es: key = get_or_save_email_subscriber(email, 'settings') es.preferences['level'] = level es.email = email form = dict(request.POST) # form was not sending falses, so default them if not there for email_tuple in ALL_EMAILS: key = email_tuple[0] if key not in form.keys(): form[key] = False es.build_email_preferences(form) es = record_form_submission(request, es, 'email') ip = get_ip(request) es.active = level != 'nothing' es.newsletter = level in ['regular', 'lite1'] if not es.metadata.get('ip', False): es.metadata['ip'] = [ip] else: es.metadata['ip'].append(ip) es.save() msg = _('Updated your preferences.') pref_lang = 'en' if not profile else profile.get_profile_preferred_language( ) context = { 'nav': 'internal', 'active': '/settings/email', 'title': _('Email Settings'), 'es': es, 'suppression_preferences': json.dumps( es.preferences.get('suppression_preferences', {}) if es else {}), 'msg': msg, 'email_types': ALL_EMAILS, 'navs': get_settings_navs(request), 'preferred_language': pref_lang } return TemplateResponse(request, 'settings/email.html', context)
def email_settings(request, key): email = '' level = '' msg = '' es = EmailSubscriber.objects.filter(priv=key) if es.exists(): email = es.first().email level = es.first().preferences.get('level', False) es = es.first() if request.POST.get('email', False): level = request.POST.get('level') comments = request.POST.get('comments')[:255] email = request.POST.get('email') github = request.POST.get('github') print(es.github) keywords = request.POST.get('keywords').split(',') validation_passed = True try: validate_email(email) except Exception as e: print(e) validation_passed = False msg = 'Invalid Email' if level not in ['lite', 'regular', 'nothing']: validation_passed = False msg = 'Invalid Level' if validation_passed: key = get_or_save_email_subscriber(email, 'settings') es = EmailSubscriber.objects.get(priv=key) es.preferences['level'] = level es.metadata['comments'] = comments es.github = github es.keywords = keywords ip = get_ip(request) es.active = level != 'nothing' es.newsletter = level in ['regular', 'lite1'] if not es.metadata.get('ip', False): es.metadata['ip'] = [ip] else: es.metadata['ip'].append(ip) es.save() msg = "Updated your preferences. " context = { 'active': 'email_settings', 'title': 'Email Settings', 'es': es, 'keywords': ",".join(es.keywords), 'msg': msg, 'autocomplete_keywords': json.dumps([ str(key) for key in Keyword.objects.all().values_list('keyword', flat=True) ]), } return TemplateResponse(request, 'email_settings.html', context)
def newkudos(request): context = { 'active': 'newkudos', 'msg': None, 'nav': 'kudos', 'title': "Mint new Kudos", 'avatar_url': request.build_absolute_uri(static('v2/images/twitter_cards/tw_cards-06.png')), } if not request.user.is_authenticated: login_redirect = redirect('/login/github/?next=' + request.get_full_path()) return login_redirect if request.POST: required_fields = ['name', 'description', 'priceFinney', 'artist', 'platform', 'numClonesAllowed', 'tags', 'to_address'] validation_passed = True for key in required_fields: if not request.POST.get(key): context['msg'] = str(_('You must provide the following fields: ')) + key validation_passed = False if validation_passed: #upload to s3 img = request.FILES.get('photo') session = boto3.Session( aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, ) s3 = session.resource('s3') key = f'media/uploads/{uuid.uuid4()}_{img.name}' response = s3.Bucket(settings.MEDIA_BUCKET).put_object(Key=key, Body=img, ACL='public-read', ContentType='image/svg+xml') artwork_url = f'https://{settings.MEDIA_BUCKET}.s3-us-west-2.amazonaws.com/{key}' # save / send email obj = TokenRequest.objects.create( profile=request.user.profile, name=request.POST['name'], description=request.POST['description'], priceFinney=request.POST['priceFinney'], artist=request.POST['artist'], bounty_url=request.POST['bounty_url'], platform=request.POST['platform'], numClonesAllowed=request.POST['numClonesAllowed'], tags=request.POST['tags'].split(","), to_address=request.POST['to_address'], artwork_url=artwork_url, network='xdai', approved=False, metadata={ 'ip': get_ip(request), 'email': request.POST.get('email'), 'pay_gas': request.POST.get('pay_gas', 0), } ) new_kudos_request(obj) context['msg'] = str(_('Your Kudos has been submitted and will be listed within 2 business days if it is accepted.')) if request.user.is_staff: if request.POST.get('mint_and_sync'): from kudos.tasks import mint_token_request mint_token_request.delay(obj.id) context['msg'] = str(_('Kudos mint/sync submitted')) return TemplateResponse(request, 'newkudos.html', context)
def receive_bulk_ethdenver(request, secret): coupons = BulkTransferCoupon.objects.filter(secret=secret) if not coupons.exists(): raise Http404 coupon = coupons.first() kudos_transfer = "" if coupon.num_uses_remaining <= 0: messages.info( request, f'Sorry but this kudos redeem link has expired! Please contact the person who sent you the coupon link, or contact your nearest Gitcoin representative.' ) return redirect(coupon.token.url) error = False if request.POST: try: address = Web3.toChecksumAddress( request.POST.get('forwarding_address')) except: error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again." if not error: address = Web3.toChecksumAddress( request.POST.get('forwarding_address')) already_claimed = KudosTransfer.objects.filter( receive_address=address, kudos_token_cloned_from=coupon.token) if already_claimed.count() > 0: messages.info( request, f'You already redeemed this kudos! If you think this wrong contact the ETHDenver Team!' ) return redirect(coupon.token.url) ip_address = get_ip(request) kudos_contract_address = Web3.toChecksumAddress( settings.KUDOS_CONTRACT_MAINNET) kudos_owner_address = Web3.toChecksumAddress( settings.KUDOS_OWNER_ACCOUNT) w3 = get_web3(coupon.token.contract.network) nonce = w3.eth.getTransactionCount(kudos_owner_address) contract = w3.eth.contract( Web3.toChecksumAddress(kudos_contract_address), abi=kudos_abi()) tx = contract.functions.clone( address, coupon.token.token_id, 1).buildTransaction({ 'nonce': nonce, 'gas': 500000, 'gasPrice': int(recommend_min_gas_price_to_confirm_in_time(1) * 10**9), 'value': int(coupon.token.price_finney / 1000.0 * 10**18), }) try: signed = w3.eth.account.signTransaction( tx, settings.KUDOS_PRIVATE_KEY) txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex() with transaction.atomic(): kudos_transfer = KudosTransfer.objects.create( emails=["*****@*****.**"], # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=coupon.token, amount=coupon.token.price_in_eth, comments_public=coupon. comments_to_put_in_kudos_transfer, ip=ip_address, github_url='', from_name=coupon.sender_profile.handle, from_email='', from_username=coupon.sender_profile.handle, network=coupon.token.contract.network, from_address=settings.KUDOS_OWNER_ACCOUNT, receive_address=address, is_for_bounty_fulfiller=False, metadata={'coupon_redemption': True}, sender_profile=coupon.sender_profile, txid=txid, receive_txid=txid, tx_status='pending', receive_tx_status='pending', ) coupon.num_uses_remaining -= 1 coupon.current_uses += 1 coupon.save() except: error = "Could not redeem your kudos. Please try again soon." title = f"Redeem ETHDenver event kudos: *{coupon.token.humanized_name}*" desc = f"Thank you for joining the event! About this Kudos: {coupon.token.description}" params = { 'title': title, 'card_title': title, 'card_desc': desc, 'error': error, 'avatar_url': coupon.token.img_url, 'coupon': coupon, 'user': request.user, 'is_authed': request.user.is_authenticated, 'kudos_transfer': kudos_transfer, } return TemplateResponse(request, 'ethdenver2019/receive_bulk.html', params)
def send_3(request): """Handle the third stage of sending a kudos (the POST). This function is derived from send_tip_3. The request to send the kudos is added to the database, but the transaction has not happened yet. The txid is added in `send_kudos_4`. Returns: JsonResponse: The response with success state. """ response = { 'status': 'OK', 'message': _('Kudos Created'), } is_user_authenticated = request.user.is_authenticated from_username = request.user.username if is_user_authenticated else '' primary_from_email = request.user.email if is_user_authenticated else '' access_token = request.user.profile.get_access_token() if is_user_authenticated and request.user.profile else '' params = json.loads(request.body) to_username = params.get('username', '').lstrip('@') to_emails = get_emails_by_category(to_username) primary_email = '' if params.get('email'): primary_email = params['email'] elif to_emails.get('primary', None): primary_email = to_emails['primary'] elif to_emails.get('github_profile', None): primary_email = to_emails['github_profile'] else: if len(to_emails.get('events', None)): primary_email = to_emails['events'][0] else: print("TODO: no email found. in the future, we should handle this case better because it's GOING to end up as a support request") if primary_email and isinstance(primary_email, list): primary_email = primary_email[0] # If no primary email in session, try the POST data. If none, fetch from GH. primary_from_email = params.get('fromEmail') if access_token and not primary_from_email: primary_from_email = get_github_primary_email(access_token) # Validate that the token exists on the back-end kudos_id = params.get('kudosId') if not kudos_id: raise Http404 try: kudos_token_cloned_from = Token.objects.get(pk=kudos_id) except Token.DoesNotExist: raise Http404 # db mutations kt = KudosTransfer.objects.create( primary_email=primary_email, emails=to_emails, # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=kudos_token_cloned_from, amount=params['amount'], comments_public=params['comments_public'], ip=get_ip(request), github_url=params['github_url'], from_name=params['from_name'], from_email=params['from_email'], from_username=from_username, username=params['username'], network=params['network'], tokenAddress=params.get('tokenAddress', ''), from_address=params['from_address'], is_for_bounty_fulfiller=params['is_for_bounty_fulfiller'], metadata=params['metadata'], recipient_profile=get_profile(to_username), sender_profile=get_profile(from_username), ) if params.get('send_type') == 'airdrop' and is_user_authenticated: num_redemptions = params['num_redemptions'] if not params.get('pk'): raise Exception('You must provide a pk') btc = BulkTransferCoupon.objects.create( token=kudos_token_cloned_from, num_uses_remaining=num_redemptions, num_uses_total=num_redemptions, current_uses=0, secret=random.randint(10**19, 10**20), comments_to_put_in_kudos_transfer=params['comments_public'], sender_address=params['metadata']['address'], sender_pk=params.get('pk'), sender_profile=get_profile(from_username), ) response['url'] = btc.url return JsonResponse(response)
def preprocess(request): """Handle inserting pertinent data into the current context.""" # make lbcheck super lightweight if request.path == '/lbcheck': return {} ptoken = None search_url = '' user_is_authenticated = request.user.is_authenticated profile = request.user.profile if user_is_authenticated and hasattr( request.user, 'profile') else None if user_is_authenticated and profile and profile.pk: # what actions to take? record_join = not profile.last_visit record_visit = not profile.last_visit or profile.last_visit < ( timezone.now() - timezone.timedelta(seconds=RECORD_VISIT_EVERY_N_SECONDS)) if record_visit: try: profile.last_visit = timezone.now() profile.save() except Exception as e: logger.exception(e) try: from dashboard.tasks import profile_dict profile_dict.delay(profile.pk) except Exception as e: logger.exception(e) metadata = { 'visitorId': request.COOKIES.get("visitorId", None), 'useragent': request.META['HTTP_USER_AGENT'], 'referrer': request.META.get('HTTP_REFERER', None), 'path': request.META.get('PATH_INFO', None), 'session_key': request.session._session_key, } ip_address = get_ip(request) UserAction.objects.create( user=request.user, profile=profile, action='Visit', location_data=get_location_from_ip(ip_address), ip_address=ip_address, utm=_get_utm_from_cookie(request), metadata=metadata, ) if record_join: Activity.objects.create(profile=profile, activity_type='joined') ptoken = PersonalToken.objects.filter( token_owner_profile=profile).first() # Check if user's location supports pTokens try: current_location = profile.locations[-1] is_location_blocked_for_ptokens = current_location['country_code'] == settings.PTOKEN_BLOCKED_REGION['country_code'] \ and current_location['region'] == settings.PTOKEN_BLOCKED_REGION['region'] except: # If user is not logged in is_location_blocked_for_ptokens = False # handles marketing callbacks if request.GET.get('cb'): callback = request.GET.get('cb') handle_marketing_callback(callback, request) header_msg, footer_msg, nav_salt = get_sitewide_announcements() try: onboard_tasks = JSONStore.objects.get(key='onboard_tasks').data except JSONStore.DoesNotExist: onboard_tasks = [] # town square wall post max length max_length_offset = abs( ((request.user.profile.created_on if hasattr(request.user, 'profile') and request.user.is_authenticated else timezone.now()) - timezone.now()).days) max_length = 600 + max_length_offset context = { 'STATIC_URL': settings.STATIC_URL, 'MEDIA_URL': settings.MEDIA_URL, 'max_length': max_length, 'max_length_offset': max_length_offset, 'search_url': f'{settings.BASE_URL}user_lookup', 'base_url': settings.BASE_URL, 'github_handle': request.user.username.lower() if user_is_authenticated else False, 'email': request.user.email if user_is_authenticated else False, 'name': request.user.get_full_name() if user_is_authenticated else False, 'raven_js_version': settings.RAVEN_JS_VERSION, 'raven_js_dsn': settings.SENTRY_JS_DSN, 'release': settings.RELEASE, 'env': settings.ENV, 'header_msg': header_msg, 'nav_salt': nav_salt, 'footer_msg': footer_msg, 'INFURA_V3_PROJECT_ID': settings.INFURA_V3_PROJECT_ID, 'giphy_key': settings.GIPHY_KEY, 'youtube_key': settings.YOUTUBE_API_KEY, 'fortmatic_live_key': settings.FORTMATIC_LIVE_KEY, 'fortmatic_test_key': settings.FORTMATIC_TEST_KEY, 'orgs': profile.organizations if profile else [], 'profile_id': profile.id if profile else '', 'is_pro': profile.is_pro if profile else False, 'hotjar': settings.HOTJAR_CONFIG, 'ipfs_config': { 'host': settings.JS_IPFS_HOST, 'port': settings.IPFS_API_PORT, 'protocol': settings.IPFS_API_SCHEME, 'root': settings.IPFS_API_ROOT, }, 'access_token': profile.access_token if profile else '', 'is_staff': request.user.is_staff if user_is_authenticated else False, 'is_moderator': profile.is_moderator if profile else False, 'is_alpha_tester': profile.is_alpha_tester if profile else False, 'user_groups': list(profile.user_groups) if profile else False, 'persona_is_funder': profile.persona_is_funder if profile else False, 'persona_is_hunter': profile.persona_is_hunter if profile else False, 'pref_do_not_track': profile.pref_do_not_track if profile else False, 'profile_url': profile.url if profile else False, 'quests_live': settings.QUESTS_LIVE, 'onboard_tasks': onboard_tasks, 'ptoken_abi': settings.PTOKEN_ABI, 'ptoken_factory_address': settings.PTOKEN_FACTORY_ADDRESS, 'ptoken_factory_abi': settings.PTOKEN_FACTORY_ABI, 'ptoken_address': ptoken.token_address if ptoken else '', 'ptoken_id': ptoken.id if ptoken else None, 'is_location_blocked_for_ptokens': is_location_blocked_for_ptokens, 'match_payouts_abi': settings.MATCH_PAYOUTS_ABI, 'match_payouts_address': settings.MATCH_PAYOUTS_ADDRESS, 'mautic_id': profile.mautic_id if profile else None, } context['json_context'] = json.dumps(context) context['last_posts'] = cache.get_or_set('last_posts', fetchPost, 5000) if context['github_handle']: context['unclaimed_tips'] = Tip.objects.filter( receive_txid='', username__iexact=context['github_handle'], web3_type='v3', ).send_happy_path().cache(timeout=60) context['unclaimed_kudos'] = KudosTransfer.objects.filter( receive_txid='', username__iexact="@" + context['github_handle'], web3_type='v3', ).send_happy_path().cache(timeout=60) if not settings.DEBUG: context['unclaimed_tips'] = context['unclaimed_tips'].filter( network='mainnet').cache(timeout=60) context['unclaimed_kudos'] = context['unclaimed_kudos'].filter( network='mainnet').cache(timeout=60) return context