def helper_handle_access_token(request, access_token): # https://gist.github.com/owocki/614a18fbfec7a5ed87c97d37de70b110 # interest API via token github_user_data = get_github_user_data(access_token) request.session['handle'] = github_user_data['login'] profile = Profile.objects.filter(handle__iexact=request.session['handle']).first() request.session['profile_id'] = profile.pk
def remove_interest(request, bounty_id): """Unclaim work from the Bounty. Can only be called by someone who has started work :request method: POST post_id (int): ID of the Bounty. Returns: dict: The success key with a boolean value and accompanying error. """ profile_id = request.user.profile.pk if request.user.is_authenticated and hasattr(request.user, 'profile') else None access_token = request.GET.get('token') if access_token: helper_handle_access_token(request, access_token) github_user_data = get_github_user_data(access_token) profile = Profile.objects.filter(handle=github_user_data['login']).first() profile_id = profile.pk if not profile_id: return JsonResponse( {'error': _('You must be authenticated via github to use this feature!')}, status=401) try: bounty = Bounty.objects.get(pk=bounty_id) except Bounty.DoesNotExist: return JsonResponse({'errors': ['Bounty doesn\'t exist!']}, status=401) try: interest = Interest.objects.get(profile_id=profile_id, bounty=bounty) record_user_action(request.user, 'stop_work', interest) bounty.interested.remove(interest) interest.delete() maybe_market_to_slack(bounty, 'stop_work') maybe_market_to_user_slack(bounty, 'stop_work') maybe_market_to_twitter(bounty, 'stop_work') except Interest.DoesNotExist: return JsonResponse({ 'errors': [_('You haven\'t expressed interest on this bounty.')], 'success': False}, status=401) except Interest.MultipleObjectsReturned: interest_ids = bounty.interested \ .filter( profile_id=profile_id, bounty=bounty ).values_list('id', flat=True) \ .order_by('-created') bounty.interested.remove(*interest_ids) Interest.objects.filter(pk__in=list(interest_ids)).delete() return JsonResponse({'success': True})
def test_get_github_user_data_failure(self): """Test the github utility get_github_user_data method.""" headers = dict({'Authorization': f'token {self.user_oauth_token}'}, **JSON_HEADER) data = {'login': '******'} responses.add(responses.GET, 'https://api.github.com/user', json=data, headers=headers, status=404) result = get_github_user_data(self.user_oauth_token) assert result == {}
def github_callback(request): """Handle the Github authentication callback.""" # Get request parameters to handle authentication and the redirect. code = request.GET.get('code', None) redirect_uri = request.GET.get('redirect_uri') if not code or not redirect_uri: raise Http404 # Get OAuth token and github user data. access_token = get_github_user_token(code) github_user_data = get_github_user_data(access_token) handle = github_user_data.get('login') ip_address = '24.210.224.38' if settings.DEBUG else get_real_ip(request) geolocation_data = {} if ip_address: geolocation_data = get_location_from_ip(ip_address) if handle: # Create or update the Profile with the github user data. user_profile, _ = Profile.objects.update_or_create( handle=handle, defaults={ 'data': github_user_data or {}, 'email': get_github_primary_email(access_token), 'github_access_token': access_token }) # Update the user's session with handle and email info. session_data = { 'handle': user_profile.handle, 'email': user_profile.email, 'access_token': user_profile.github_access_token, 'profile_id': user_profile.pk, 'name': user_profile.data.get('name', None), 'access_token_last_validated': timezone.now().isoformat(), } for k, v in session_data.items(): request.session[k] = v # record a useraction for this UserAction.objects.create(profile=user_profile, action='Login', metadata={}, ip_address=ip_address, location_data=geolocation_data) response = redirect(redirect_uri) response.set_cookie('last_github_auth_mutation', int(time.time())) return response
def github_callback(request): """Handle the Github authentication callback.""" # Get request parameters to handle authentication and the redirect. code = request.GET.get('code', None) redirect_uri = request.GET.get('redirect_uri') if not code or not redirect_uri: raise Http404 # Get OAuth token and github user data. access_token = get_github_user_token(code) github_user_data = get_github_user_data(access_token) handle = github_user_data.get('login') github_repos = get_github_repos(access_token) if handle: # Create or update the Profile with the github user data. # user_profile, _ = Profile.objects.update_or_create( # handle=handle, # defaults={ # 'data': github_user_data or {}, # 'email': get_github_primary_email(access_token), # 'github_access_token': access_token # }) # Update the user's session with handle and email info. session_data = { 'handle': handle, 'user_repos': github_repos, 'email': get_github_primary_email(access_token), 'access_token': access_token, 'name': github_user_data.get('name', None), 'access_token_last_validated': timezone.now().isoformat(), } for k, v in session_data.items(): request.session[k] = v # # record a useraction for this # UserAction.objects.create( # profile=user_profile, # action='Login', # metadata={}, # ) response = redirect(redirect_uri) response.set_cookie('last_github_auth_mutation', int(time.time())) return response
def github_callback(request): """Handle the Github authentication callback.""" # Get request parameters to handle authentication and the redirect. code = request.GET.get('code', None) redirect_uri = request.GET.get('redirect_uri') if not code or not redirect_uri: raise Http404 # Get OAuth token and github user data. access_token = get_github_user_token(code) github_user_data = get_github_user_data(access_token) handle = github_user_data.get('login') if handle: # Create or update the Profile with the github user data. user_profile, _ = Profile.objects.update_or_create( handle=handle, defaults={ 'data': github_user_data or {}, 'email': get_github_primary_email(access_token), 'github_access_token': access_token }) # Update the user's session with handle and email info. session_data = { 'handle': user_profile.handle, 'email': user_profile.email, 'access_token': user_profile.github_access_token, 'profile_id': user_profile.pk, 'access_token_last_validated': timezone.now().isoformat(), } for k, v in session_data.items(): request.session[k] = v response = redirect(redirect_uri) response.set_cookie('last_github_auth_mutation', int(time.time())) return response
def new_interest(request, bounty_id): """Claim Work for a Bounty. :request method: POST Args: bounty_id (int): ID of the Bounty. Returns: dict: The success key with a boolean value and accompanying error. """ profile_id = request.user.profile.pk if request.user.is_authenticated and hasattr( request.user, 'profile') else None access_token = request.GET.get('token') if access_token: helper_handle_access_token(request, access_token) github_user_data = get_github_user_data(access_token) profile = Profile.objects.prefetch_related('bounty_set') \ .filter(handle=github_user_data['login']).first() profile_id = profile.pk else: profile = request.user.profile if profile_id else None if not profile_id: return JsonResponse( { 'error': _('You must be authenticated via github to use this feature!') }, status=401) try: bounty = Bounty.objects.get(pk=bounty_id) except Bounty.DoesNotExist: raise Http404 num_issues = profile.max_num_issues_start_work active_bounties = Bounty.objects.current().filter( idx_status__in=['open', 'started']) num_active = Interest.objects.filter(profile_id=profile_id, bounty__in=active_bounties).count() is_working_on_too_much_stuff = num_active >= num_issues if is_working_on_too_much_stuff: return JsonResponse( { 'error': _(f'You may only work on max of {num_issues} issues at once.'), 'success': False }, status=401) if profile.has_been_removed_by_staff(): return JsonResponse( { 'error': _('Because a staff member has had to remove you from a bounty in the past, you are unable to start more work at this time. Please contact support.' ), 'success': False }, status=401) try: Interest.objects.get(profile_id=profile_id, bounty=bounty) return JsonResponse( { 'error': _('You have already expressed interest in this bounty!'), 'success': False }, status=401) except Interest.DoesNotExist: issue_message = request.POST.get("issue_message") interest = create_new_interest_helper(bounty, request.user, issue_message) except Interest.MultipleObjectsReturned: bounty_ids = bounty.interested \ .filter(profile_id=profile_id) \ .values_list('id', flat=True) \ .order_by('-created')[1:] Interest.objects.filter(pk__in=list(bounty_ids)).delete() return JsonResponse( { 'error': _('You have already expressed interest in this bounty!'), 'success': False }, status=401) return JsonResponse({ 'success': True, 'profile': ProfileSerializer(interest.profile).data })
def save(request): status = 422 message = 'Please use a POST' body = {} try: body = json.loads(request.body) except Exception: status = 400 message = 'Bad Request' if body.get('bounty_id', False): access_token = body.get('token') if body.get( 'token') else request.GET.get('token') github_username = body.get('github_username') try: github_user_data = get_github_user_data(access_token) except Exception: github_user_data = {} access_token_invalid = not access_token or github_user_data.get( 'login') != github_username if access_token_invalid: status = 405 message = f'Not authorized or invalid github token for github user {github_username}' else: # handle a POST bounty_id = body.get('bounty_id') email_address = body.get('email_address') direction = body.get('direction') # do validation validation_failed = False # email try: validate_email(email_address) except ValidationError: validation_failed = 'email' # bounty if not Bounty.objects.filter(pk=bounty_id).exists(): validation_failed = 'bounty does not exist' # direction if direction not in ['+', '-']: validation_failed = 'direction must be either + or -' # github_username if not github_username: validation_failed = 'no github_username' # handle validation failures if validation_failed: status = 422 message = f'Validation failed: {validation_failed}' else: bounty = Bounty.objects.get(pk=bounty_id) # save obj Match.objects.create( bounty=bounty, email=email_address, direction=direction, github_username=github_username, ) try: if direction == '+': profiles = Profile.objects.filter( handle=github_username) profile = profiles.first() if profiles.exists( ) else None interest = Interest.objects.create( profile_id=profile.pk) bounty.interested.add(interest) # TODO -- user create_new_interest_helper except Exception as e: print(f'could not get profile {e}') logging.exception(e) # send match email if direction == '+': to_emails = [email_address, bounty.bounty_owner_email] new_match(to_emails, bounty, github_username) # response status = 200 message = 'Success' response = { 'status': status, 'message': message, } return JsonResponse(response, status=status)