def test_get_user_subpath(self): """Test the github utility get_user method with a subpath.""" url = 'https://api.github.com/users/gitcoin/test' responses.add(responses.GET, url, headers=HEADERS, json={}, status=200) get_user('@gitcoin', '/test') assert responses.calls[0].request.url == url
def sync_profile(handle): data = get_user(handle) is_error = 'name' not in data.keys() if is_error: print("- error main") return repos_data = get_user(handle, '/repos') repos_data = sorted(repos_data, key=lambda repo: repo['stargazers_count'], reverse=True) repos_data = [add_contributors(repo_data) for repo_data in repos_data] # store the org info in postgres org, _ = Profile.objects.get_or_create( handle=handle, defaults={ 'last_sync_date': timezone.now(), 'data': data, 'repos_data': repos_data, }, ) org.handle = handle org.data = data org.repos_data = repos_data org.save() print("- updated")
def sync_profile(handle): data = get_user(handle) is_error = 'name' not in data.keys() if is_error: print("- error main") rollbar.report_message('Failed to fetch github username', 'warning', extra_data=data) return None repos_data = get_user(handle, '/repos') repos_data = sorted(repos_data, key=lambda repo: repo['stargazers_count'], reverse=True) repos_data = [add_contributors(repo_data) for repo_data in repos_data] # store the org info in postgres try: profile, created = Profile.objects.update_or_create( handle=handle, defaults={ 'last_sync_date': timezone.now(), 'data': data, 'repos_data': repos_data, }) print("Profile:", profile, "- created" if created else "- updated") except Exception as e: logger.error(e) return None return profile
def sync_profile(handle, user=None, hide_profile=True): data = get_user(handle) email = '' is_error = 'name' not in data.keys() if is_error: print("- error main") rollbar.report_message('Failed to fetch github username', 'warning', extra_data=data) return None repos_data = get_user(handle, '/repos') repos_data = sorted(repos_data, key=lambda repo: repo['stargazers_count'], reverse=True) repos_data = [add_contributors(repo_data) for repo_data in repos_data] defaults = { 'last_sync_date': timezone.now(), 'data': data, 'repos_data': repos_data, 'hide_profile': hide_profile, } if user and isinstance(user, User): defaults['user'] = user try: defaults['github_access_token'] = user.social_auth.filter( provider='github').latest('pk').access_token if user and user.email: defaults['email'] = user.email except UserSocialAuth.DoesNotExist: pass # store the org info in postgres try: profile, created = Profile.objects.update_or_create(handle=handle, defaults=defaults) print("Profile:", profile, "- created" if created else "- updated") except Exception as e: logger.error(e) return None if user and user.email: email = user.email elif profile and profile.email: email = profile.email if email and profile: get_or_save_email_subscriber(email, 'sync_profile', profile=profile) return profile
def get_avatar(_org_name): avatar = None filename = f"{_org_name}.png" filepath = AVATAR_BASE + filename if _org_name == 'gitcoinco': filepath = AVATAR_BASE + '../../v2/images/helmet.png' try: avatar = Image.open(filepath, 'r').convert("RGBA") except IOError: remote_user = get_user(_org_name) if not remote_user.get('avatar_url', False): return JsonResponse({'msg': 'invalid user'}, status=422) remote_avatar_url = remote_user['avatar_url'] r = requests.get(remote_avatar_url, stream=True) chunk_size = 20000 with open(filepath, 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) avatar = Image.open(filepath, 'r').convert("RGBA") # make transparent datas = avatar.getdata() new_data = [] for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: new_data.append((255, 255, 255, 0)) else: new_data.append(item) avatar.putdata(new_data) avatar.save(filepath, "PNG") return filepath
def get_avatar_url(self): try: response = get_user(self.github_org_name) return response['avatar_url'] except Exception as e: print(e) return 'https://avatars0.githubusercontent.com/u/31359507?v=4'
def github_issues(): if settings.DEBUG: return from github.utils import get_issues, get_user repos = [] for org in ['bitcoin', 'gitcoinco', 'ethereum']: for repo in get_user(org, '/repos'): repos.append((org, repo['name'])) for org, repo in repos: issues = [] cont = True page = 1 while cont: new_issues = get_issues(org, repo, page, 'all') issues = issues + new_issues page += 1 cont = len(new_issues) val = len(issues) key = f"github_issues_{org}_{repo}" try: Stat.objects.create( created_on=timezone.now(), key=key, val=(val), ) except Exception: pass if not val: break
def github_stars(): from github.utils import get_user reops = get_user('gitcoinco', '/repos') forks_count = sum([repo['forks_count'] for repo in reops]) Stat.objects.create( key='github_forks_count', val=forks_count, ) stargazers_count = sum([repo['stargazers_count'] for repo in reops]) Stat.objects.create( key='github_stargazers_count', val=stargazers_count, )
def get_github_avatar(handle): """Pull the latest avatar from Github and store in Avatar.png. Returns: bool: Whether or not the Github avatar was updated. """ remote_user = get_user(handle) avatar_url = remote_user.get('avatar_url') if not avatar_url: return False temp_avatar = get_temp_image_file(avatar_url) if not temp_avatar: return False return temp_avatar
def sync_profile_actions(self): # figure out what github profiles we care about hours = 100 if settings.DEBUG else 24 start = timezone.now() - timezone.timedelta(hours=hours) profile_ids_logged_in_last_time_period = list( UserAction.objects.filter(created_on__gt=start, action="Login").values_list('profile', flat=True)) profile_ids_interest_last_time_period = list( Interest.objects.filter(created__gt=start).values_list('profile', flat=True)) profile_ids_fulfilled_last_time_period = list( BountyFulfillment.objects.filter(created_on__gt=start).values_list( 'profile', flat=True)) profile_ids = profile_ids_interest_last_time_period + profile_ids_logged_in_last_time_period + profile_ids_fulfilled_last_time_period profiles = Profile.objects.filter(pk__in=profile_ids) # process them for profile in profiles: try: events = get_user(profile.handle, '/events') for event in events: try: event_time = event.get('created_at', False) created_on = datetime.datetime.strptime( event_time, '%Y-%m-%dT%H:%M:%SZ') except Exception: created_on = timezone.now() if self.do_we_care(event): GithubEvent.objects.get_or_create( profile=profile, payload=event, what=event.get('type', ''), repo=event.get('repo', {}).get('name', ''), created_on=created_on, ) except Exception as e: print(e)
def github_issues(): from django.utils import timezone from datetime import datetime from marketing.models import Stat from github.utils import get_issues, get_user import pytz repos = [ ] for org in ['bitcoin', 'gitcoinco', 'ethereum']: for repo in get_user(org, '/repos'): repos.append((org, repo['name'])) for org, repo in repos: issues = [] cont = True page = 1 while cont: new_issues = get_issues(org, repo, page, 'all') issues = issues + new_issues page += 1 cont = len(new_issues) val = len(issues) key = f"github_issues_{org}_{repo}" try: Stat.objects.create( created_on=timezone.now(), key=key, val=(val), ) except: pass if not val: break print(key, val)
def embed(request): # default response could_not_find = Image.new('RGBA', (1, 1), (0, 0, 0, 0)) err_response = HttpResponse(content_type="image/jpeg") could_not_find.save(err_response, "JPEG") # params repo_url = request.GET.get('repo', False) if not repo_url or 'github.com' not in repo_url: return err_response try: # get avatar of repo _org_name = org_name(repo_url) is_org_gitcoin = _org_name == 'gitcoinco' avatar = None filename = "{}.png".format(_org_name) filepath = 'assets/other/avatars/' + filename try: avatar = Image.open(filepath, 'r').convert("RGBA") except IOError: remote_user = get_user(_org_name) if not remote_user.get('avatar_url', False): return JsonResponse({'msg': 'invalid user'}, status=422) remote_avatar_url = remote_user['avatar_url'] r = requests.get(remote_avatar_url, stream=True) chunk_size = 20000 with open(filepath, 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) avatar = Image.open(filepath, 'r').convert("RGBA") # make transparent datas = avatar.getdata() newData = [] for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: newData.append((255, 255, 255, 0)) else: newData.append(item) avatar.putdata(newData) avatar.save(filepath, "PNG") # get issues length = request.GET.get('len', 10) super_bounties = Bounty.objects.current().filter( github_url__startswith=repo_url, network='mainnet', idx_status='open').order_by('-_val_usd_db') bounties = super_bounties[:length] # config bounty_height = 145 bounty_width = 400 font_path = 'marketing/quotify/fonts/' width = 1350 height = 350 spacing = 0 line = "".join(["_" for ele in range(0, 47)]) # setup img = Image.new("RGBA", (width, height), (255, 255, 255)) black = (0, 0, 0) h1 = ImageFont.truetype(font_path + 'Futura-Bold.ttf', 28, encoding="unic") h2_thin = ImageFont.truetype(font_path + 'Futura-Normal.ttf', 22, encoding="unic") p = ImageFont.truetype(font_path + 'Futura-LightBT.ttf', 20, encoding="unic") # background ## config logo = 'assets/v2/images/header-bg-light.jpg' ## execute back = Image.open(logo, 'r').convert("RGBA") img_w, img_h = back.size bg_w, bg_h = img.size offset = 0, 0 img.paste(back, offset) # repo logo ## config icon_size = (215, 215) ## execute img_w, img_h = avatar.size avatar.thumbnail(icon_size, Image.ANTIALIAS) bg_w, bg_h = img.size offset = 10, 10 img.paste(avatar, offset, avatar) # gitcoin logo ## config logo = 'assets/v2/images/gitcoinco.png' ## execute back = Image.open(logo, 'r').convert("RGBA") back.thumbnail(icon_size, Image.ANTIALIAS) img_w, img_h = back.size bg_w, bg_h = img.size offset = 250, 10 if not is_org_gitcoin: img.paste(back, offset, back) # plus sign ## config if not is_org_gitcoin: text = '+' # execute text = wrap_text(text, 20) draw = ImageDraw.Draw(img) img_w, img_h = img.size x = 225 y = 60 draw.multiline_text(align="center", xy=(x, y), text=text, fill=black, font=h1, spacing=spacing) draw = ImageDraw.Draw(img) # header ## config text = '{} Supports Funded Issues'.format(_org_name.title()) # execute text = wrap_text(text, 30) draw = ImageDraw.Draw(img) img_w, img_h = img.size x = 10 y = 200 draw.multiline_text(align="left", xy=(x, y), text=text, fill=black, font=h1, spacing=spacing) draw = ImageDraw.Draw(img) ## config show_value, value = summarize_bounties(super_bounties) text = '{}\nPush Open Source Forward | Powered by Gitcoin.co'.format( wrap_text(value, 45) if show_value else "") # execute draw = ImageDraw.Draw(img) img_w, img_h = img.size x = 10 y = 225 draw.multiline_text(align="left", xy=(x, y), text=text, fill=black, font=h2_thin, spacing=12) draw = ImageDraw.Draw(img) # put bounty list in there i = 0 for bounty in bounties: i += 1 text = f"{line}\n{wrap_text(bounty.title_or_desc, 30)}\n\nWorth: " \ f"{round(bounty.value_true, 2)} {bounty.token_name} ({round(bounty.value_in_usdt, 2)} USD " \ f"@ ${round(convert_token_to_usdt(bounty.token_name), 2)}/{bounty.token_name})" # execute draw = ImageDraw.Draw(img) img_w, img_h = img.size line_size = 2 x = 500 + (int((i - 1) / line_size) * (bounty_width)) y = 30 + (abs(i % line_size - 1) * bounty_height) draw.multiline_text(align="left", xy=(x, y), text=text, fill=black, font=p, spacing=spacing) draw = ImageDraw.Draw(img) if bounties.count() == 0: text = "{}\n\n{}\n\n{}".format( line, wrap_text( "No active issues. Post a funded issue at https://gitcoin.co", 50), line) # execute draw = ImageDraw.Draw(img) img_w, img_h = img.size x = 10 y = 320 draw.multiline_text(align="left", xy=(x, y), text=text, fill=black, font=p, spacing=spacing) draw = ImageDraw.Draw(img) if bounties.count() != 0: ## config text = 'Browse Issues @ https://gitcoin.co/explorer' # execute text = wrap_text(text, 20) draw = ImageDraw.Draw(img) img_w, img_h = img.size x = 10 y = height - 50 draw.multiline_text(align="center", xy=(x, y), text=text, fill=black, font=h2_thin, spacing=spacing) draw = ImageDraw.Draw(img) response = HttpResponse(content_type="image/jpeg") img.save(response, "JPEG") return response except IOError as e: print(e) return err_response
def avatar(request): # default response could_not_find = Image.new('RGBA', (1, 1), (0, 0, 0, 0)) err_response = HttpResponse(content_type="image/jpeg") could_not_find.save(err_response, "JPEG") # params repo_url = request.GET.get('repo', False) if not repo_url or 'github.com' not in repo_url: return err_response try: # get avatar of repo _org_name = org_name(repo_url) avatar = None filename = "{}.png".format(_org_name) filepath = 'assets/other/avatars/' + filename try: avatar = Image.open(filepath, 'r').convert("RGBA") except IOError: remote_user = get_user(_org_name) if not remote_user.get('avatar_url', False): return JsonResponse({'msg': 'invalid user'}, status=422) remote_avatar_url = remote_user['avatar_url'] r = requests.get(remote_avatar_url, stream=True) chunk_size = 20000 with open(filepath, 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) avatar = Image.open(filepath, 'r').convert("RGBA") # make transparent datas = avatar.getdata() newData = [] for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: newData.append((255, 255, 255, 0)) else: newData.append(item) avatar.putdata(newData) avatar.save(filepath, "PNG") width, height = (215, 215) img = Image.new("RGBA", (width, height), (255, 255, 255)) ## config icon_size = (215, 215) ## execute avatar = ImageOps.fit(avatar, icon_size, Image.ANTIALIAS) bg_w, bg_h = img.size offset = 0, 0 img.paste(avatar, offset, avatar) response = HttpResponse(content_type="image/jpeg") img.save(response, "JPEG") return response except IOError as e: print(e) return err_response
def embed(request): # default response could_not_find = Image.new('RGBA', (1, 1), (0, 0, 0, 0)) err_response = HttpResponse(content_type="image/jpeg") could_not_find.save(err_response, "JPEG") # params repo_url = request.GET.get('repo', False) if not repo_url or 'github.com' not in repo_url: return err_response try: # get avatar of repo _org_name = org_name(repo_url) avatar = None filename = f"{_org_name}.png" filepath = 'assets/other/avatars/' + filename try: avatar = Image.open(filepath, 'r').convert("RGBA") except IOError: remote_user = get_user(_org_name) if not remote_user.get('avatar_url', False): return JsonResponse({'msg': 'invalid user'}, status=422) remote_avatar_url = remote_user['avatar_url'] r = requests.get(remote_avatar_url, stream=True) chunk_size = 20000 with open(filepath, 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) avatar = Image.open(filepath, 'r').convert("RGBA") # make transparent datas = avatar.getdata() new_data = [] for item in datas: if item[0] == 255 and item[1] == 255 and item[2] == 255: new_data.append((255, 255, 255, 0)) else: new_data.append(item) avatar.putdata(new_data) avatar.save(filepath, "PNG") # get issues length = request.GET.get('len', 10) super_bounties = Bounty.objects.current() \ .filter( github_url__startswith=repo_url, network='mainnet', idx_status__in=['open', 'started', 'submitted'] ).order_by('-_val_usd_db') bounties = super_bounties[:length] # config bounty_height = 200 bounty_width = 572 font = 'assets/v2/fonts/futura/FuturaStd-Medium.otf' width = 1776 height = 576 # setup img = Image.new("RGBA", (width, height), (255, 255, 255)) draw = ImageDraw.Draw(img) black = (0, 0, 0) gray = (102, 102, 102) h1 = ImageFont.truetype(font, 36, encoding="unic") h2_thin = ImageFont.truetype(font, 36, encoding="unic") p = ImageFont.truetype(font, 24, encoding="unic") # background background_image = 'assets/v2/images/embed-widget/background.png' back = Image.open(background_image, 'r').convert("RGBA") offset = 0, 0 img.paste(back, offset) # repo logo icon_size = (184, 184) avatar.thumbnail(icon_size, Image.ANTIALIAS) offset = 195, 148 img.paste(avatar, offset, avatar) img_org_name = ImageDraw.Draw(img) img_org_name_size = img_org_name.textsize(_org_name, h1) img_org_name.multiline_text( align="left", xy=(287 - img_org_name_size[0] / 2, 360), text=_org_name, fill=black, font=h1, ) draw.multiline_text( align="left", xy=(110, 410), text="supports funded issues", fill=black, font=h1, ) # put bounty list in there i = 0 for bounty in bounties[:4]: i += 1 # execute line_size = 2 # Limit text to 28 chars text = f"{bounty.title_or_desc}" text = (text[:28] + '...') if len(text) > 28 else text x = 620 + (int((i - 1) / line_size) * (bounty_width)) y = 230 + (abs(i % line_size - 1) * bounty_height) draw.multiline_text(align="left", xy=(x, y), text=text, fill=black, font=h2_thin) unit = 'day' num = int(round((bounty.expires_date - timezone.now()).days, 0)) if num == 0: unit = 'hour' num = int( round((bounty.expires_date - timezone.now()).seconds / 3600 / 24, 0)) unit = unit + ("s" if num != 1 else "") draw.multiline_text( align="left", xy=(x, y - 40), text=f"Expires in {num} {unit}:", fill=gray, font=p, ) bounty_eth_background = Image.new("RGBA", (200, 56), (231, 240, 250)) bounty_usd_background = Image.new("RGBA", (200, 56), (214, 251, 235)) img.paste(bounty_eth_background, (x, y + 50)) img.paste(bounty_usd_background, (x + 210, y + 50)) tmp = ImageDraw.Draw(img) bounty_value_size = tmp.textsize( f"{round(bounty.value_true, 2)} {bounty.token_name}", p) draw.multiline_text( align="left", xy=(x + 100 - bounty_value_size[0] / 2, y + 67), text=f"{round(bounty.value_true, 2)} {bounty.token_name}", fill=(44, 35, 169), font=p, ) bounty_value_size = tmp.textsize( f"{round(bounty.value_in_usdt_now, 2)} USD", p) draw.multiline_text( align="left", xy=(x + 310 - bounty_value_size[0] / 2, y + 67), text=f"{round(bounty.value_in_usdt_now, 2)} USD", fill=(45, 168, 116), font=p, ) # blank slate if bounties.count() == 0: draw.multiline_text( align="left", xy=(760, 320), text= "No active issues. Post a funded issue at: https://gitcoin.co", fill=gray, font=h1, ) if bounties.count() != 0: text = 'Browse issues at: https://gitcoin.co/explorer' draw.multiline_text( align="left", xy=(64, height - 70), text=text, fill=gray, font=p, ) draw.multiline_text( align="left", xy=(624, 120), text="Recently funded issues:", fill=(62, 36, 251), font=p, ) _, value = summarize_bounties(super_bounties) value_size = tmp.textsize(value, p) draw.multiline_text( align="left", xy=(1725 - value_size[0], 120), text=value, fill=gray, font=p, ) line_table_header = Image.new("RGBA", (1100, 6), (62, 36, 251)) img.paste(line_table_header, (624, 155)) # Resize back to output size for better anti-alias img = img.resize((888, 288), Image.LANCZOS) # Return image with right content-type response = HttpResponse(content_type="image/png") img.save(response, "PNG") return response except IOError as e: print(e) return err_response