def save_custom_avatar(request): """Save the Custom Avatar.""" response = {'status': 200, 'message': 'Avatar saved'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None): return JsonResponse( { 'status': 405, 'message': 'Authentication required' }, status=405) profile = request.user.profile payload = handle_avatar_payload(json.loads(request.body)) try: with transaction.atomic(): custom_avatar = CustomAvatar.create(profile, payload) custom_avatar.save() profile.activate_avatar(custom_avatar.pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) response['message'] = 'Avatar updated' except Exception as e: response['status'] = 500 response['message'] = 'Internal error' logger.error('Save Avatar - Error: (%s) - Handle: (%s)', e, profile.handle if profile else '') return JsonResponse(response, status=response['status'])
def select_preset_avatar(request): """Select preset Avatar.""" response = {'status': 200, 'message': 'Preset avatar selected'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None): return JsonResponse( { 'status': 405, 'message': 'Authentication required' }, status=405) try: with transaction.atomic(): body = json.loads(request.body) profile = request.user.profile preset_activate_pk = body['avatarPk'] preset_avatar = CustomAvatar.objects.get(pk=preset_activate_pk) selected_avatar = preset_avatar.select(profile) selected_avatar.save() profile.activate_avatar(selected_avatar.pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) except Exception as e: response['status'] = 400 response['message'] = 'Bad Request' logger.error('Save Avatar - Error: (%s) - Handle: (%s)', e, profile.handle if profile else '') return JsonResponse(response, status=response['status'])
def test_create_user_action_without_cookie(mockUserAction): """Test the giving utm* in cookie should store in DB as empty dict.""" request = RequestFactory().get('/login') create_user_action(None, 'Login', request) mockUserAction.create.assert_called_once_with(action='Login', metadata={}, user=None)
def save_custom_avatar(request, output): """Save the Custom Avatar.""" response = {'status': 200, 'message': 'Avatar saved'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None): return JsonResponse( { 'status': 405, 'message': 'Authentication required' }, status=405) profile = request.user.profile payload = dict(request.GET) try: with transaction.atomic(): custom_avatar = CustomAvatar.create_3d(profile, payload, output) custom_avatar.save() profile.activate_avatar(custom_avatar.pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) messages.info( request, f'Your avatar has been updated & will be refreshed when the cache expires (every hour). Or hard refresh (Apple-Shift-R) to view it now.' ) response['message'] = 'Avatar updated' except Exception as e: logger.exception(e) return JsonResponse(response, status=response['status'])
def test_create_user_action_with_partial_cookie(mockUserAction): """Test the giving utm* in cookie should store partial utm in DB.""" request = RequestFactory().get('/login') request.COOKIES['utm_campaign'] = 'test campaign' create_user_action(None, 'Login', request) mockUserAction.create.assert_called_once_with(action='Login', metadata={}, user=None, utm={'utm_campaign': 'test campaign'})
def discord_settings(request): """Display and save user's Discord settings. Returns: TemplateResponse: The user's Discord settings template response. """ response = {'output': ''} profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not is_logged_in: login_redirect = redirect('/login/github?next=' + request.get_full_path()) return login_redirect if request.POST: test = request.POST.get('test') submit = request.POST.get('submit') gitcoin_discord_username = request.POST.get('gitcoin_discord_username', '') webhook_url = request.POST.get('webhook_url', '') repos = request.POST.get('repos', '') if test and webhook_url: response = validate_discord_integration(webhook_url) if submit or (response and response.get('success')): profile.gitcoin_discord_username = gitcoin_discord_username profile.update_discord_integration(webhook_url, repos) profile = record_form_submission(request, profile, 'discord') if not response.get('output'): response['output'] = _('Updated your preferences.') ua_type = 'added_discord_integration' if webhook_url and repos else 'removed_discord_integration' create_user_action(user, ua_type, request, { 'webhook_url': webhook_url, 'repos': repos }) context = { 'repos': profile.get_discord_repos(join=True) if profile else [], 'gitcoin_discord_username': profile.gitcoin_discord_username, 'is_logged_in': is_logged_in, 'nav': 'home', 'active': '/settings/discord', 'title': _('Discord Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': response['output'], } return TemplateResponse(request, 'settings/discord.html', context)
def activate_avatar(request): """Activate the Avatar.""" response = {'status': 200, 'message': 'Avatar activated'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None ): return JsonResponse({'status': 405, 'message': 'Authentication required'}, status=405) body = json.loads(request.body) avatar_to_activate_pk = body['avatarPk'] profile = request.user.profile profile.activate_avatar(avatar_to_activate_pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) return JsonResponse(response, status=response['status'])
def slack_settings(request): """Displays and saves user's slack settings. Returns: TemplateResponse: The user's slack settings template response. """ response = {'output': ''} profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not is_logged_in: login_redirect = redirect('/login/github?next=' + request.get_full_path()) return login_redirect if request.POST: test = request.POST.get('test') submit = request.POST.get('submit') token = request.POST.get('token', '') repos = request.POST.get('repos', '') channel = request.POST.get('channel', '') if test and token and channel: response = validate_slack_integration(token, channel) if submit or (response and response.get('success')): profile.update_slack_integration(token, channel, repos) profile = record_form_submission(request, profile, 'slack') if not response.get('output'): response['output'] = _('Updated your preferences.') ua_type = 'added_slack_integration' if token and channel and repos else 'removed_slack_integration' create_user_action(user, ua_type, request, { 'channel': channel, 'repos': repos }) context = { 'repos': profile.get_slack_repos(join=True) if profile else [], 'is_logged_in': is_logged_in, 'nav': 'internal', 'active': '/settings/slack', 'title': _('Slack Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': response['output'], } return TemplateResponse(request, 'settings/slack.html', context)
def ens_settings(request): """Displays and saves user's ENS settings. Returns: TemplateResponse: The user's ENS settings template response. """ response = {'output': ''} profile, es, user, is_logged_in = settings_helper_get_auth(request) if not user or not is_logged_in: login_redirect = redirect('/login/github?next=' + request.get_full_path()) return login_redirect ens_subdomains = ENSSubdomainRegistration.objects.filter( profile=profile).order_by('-pk') ens_subdomain = ens_subdomains.first() if ens_subdomains.exists() else None if request.POST: if test and token and channel: response = validate_slack_integration(token, channel) if submit or (response and response.get('success')): profile.update_slack_integration(token, channel, repos) if not response.get('output'): response['output'] = _('Updated your preferences.') ua_type = 'added_slack_integration' if token and channel and repos else 'removed_slack_integration' create_user_action(user, ua_type, request, { 'channel': channel, 'repos': repos }) context = { 'is_logged_in': is_logged_in, 'nav': 'internal', 'ens_subdomain': ens_subdomain, 'active': '/settings/ens', 'title': _('ENS Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': response['output'], } return TemplateResponse(request, 'settings/ens.html', context)
def save_avatar(request): """Save the Avatar configuration.""" response = {'status': 200, 'message': 'Avatar saved'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None): return JsonResponse( { 'status': 405, 'message': 'Authentication required' }, status=405) profile = request.user.profile if request.body and 'use_github_avatar' in str(request.body): if not profile.avatar: profile.avatar = Avatar.objects.create() profile.save() profile.avatar.use_github_avatar = True avatar_url = profile.avatar.pull_github_avatar() response['message'] = 'Avatar updated' response['avatar_url'] = avatar_url return JsonResponse(response, status=200) payload = handle_avatar_payload(request) try: if not profile.avatar: profile.avatar = Avatar.objects.create(config=payload, use_github_avatar=False) profile.save() else: profile.avatar.config = payload profile.avatar.use_github_avatar = False profile.avatar.save() response['message'] = 'Avatar updated' profile.avatar.create_from_config() profile.avatar.save() create_user_action(profile.user, 'updated_avatar', request) except Exception as e: response['status'] = 400 response['message'] = 'Bad Request' logger.error('Save Avatar - Error: (%s) - Handle: (%s)', e, profile.handle if profile else '') return JsonResponse(response, status=response['status'])
def save_custom_avatar(request, output): """Save the Custom Avatar.""" response = {'status': 200, 'message': 'Avatar saved'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None ): return JsonResponse({'status': 405, 'message': 'Authentication required'}, status=405) profile = request.user.profile payload = dict(request.GET) try: with transaction.atomic(): custom_avatar = CustomAvatar.create_3d(profile, payload, output) custom_avatar.save() profile.activate_avatar(custom_avatar.pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) response['message'] = 'Avatar updated' except Exception as e: logger.exception(e) return JsonResponse(response, status=response['status'])
def save_github_avatar(request): """Save the Github Avatar.""" response = {'status': 200, 'message': 'Avatar saved'} if not request.user.is_authenticated or request.user.is_authenticated and not getattr( request.user, 'profile', None ): return JsonResponse({'status': 405, 'message': 'Authentication required'}, status=405) profile = request.user.profile github_avatar_img = get_user_github_avatar_image(profile.handle) if not github_avatar_img: return JsonResponse(response, status=response['status']) with transaction.atomic(): github_avatar = SocialAvatar.github_avatar(profile, github_avatar_img) github_avatar.save() profile.activate_avatar(github_avatar.pk) profile.save() create_user_action(profile.user, 'updated_avatar', request) response['message'] = 'Avatar updated' response['avatar_url'] = github_avatar.avatar_url return JsonResponse(response, status=response['status'])
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(): 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/job', 'title': _('Job Settings'), 'navs': get_settings_navs(request), 'es': es, 'profile': profile, 'msg': msg, } return TemplateResponse(request, 'settings/job.html', 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 delete_user_from_mailchimp(es.email) 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 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', 'From Location', 'To', 'To Location', 'Type', 'Value In USD', 'url', 'txid', 'token_name', 'token_value' ]) profile = request.user.profile earnings = profile.earnings if export_type == 'earnings' else profile.sent_earnings earnings = earnings.filter( network='mainnet').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.from_profile.data.get('location', 'Unknown') if earning.from_profile else 'Unknown', earning.to_profile.handle if earning.to_profile else '*', earning.to_profile.data.get('location', 'Unknown') if earning.to_profile else 'Unknown', earning.source_type.model_class(), earning.value_usd, earning.txid, earning.token_name, earning.token_value, 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.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 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 post_logout(sender, request, user, **kwargs): """Handle actions to take on user logout.""" from dashboard.utils import create_user_action create_user_action(user, 'Logout', request)
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(): 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=/') 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)