예제 #1
0
 def github_url(self):
     """Return the Github repository URL."""
     if "https://github.com" not in self.action_url:
         raise Exception("not a github url")
     _repo_name = repo_name(self.action_url)
     _org_name = org_name(self.action_url)
     return f"https://github.com/{_org_name}/{_repo_name}"
예제 #2
0
def handle_avatar(request, _org_name='', add_gitcoincologo=False):
    from dashboard.models import Profile
    icon_size = (215, 215)

    if _org_name:
        _org_name = _org_name.replace('@', '')

    if is_blocked(_org_name) or is_deleted_account(_org_name):
        return get_err_response(request, blank_img=(_org_name == 'Self'))

    if _org_name:
        try:
            profile = Profile.objects.prefetch_related('avatar_baseavatar_related')\
                .filter(handle=_org_name.lower()).first()
            if profile and profile.active_avatar_nocache:
                avatar_file, content_type = profile.active_avatar_nocache.determine_response(
                    request.GET.get('email', False)
                )
                if avatar_file:
                    return HttpResponse(avatar_file, content_type=content_type)
        except Exception as e:
            logger.error('Handle Avatar - Exception: (%s) - Handle: (%s)', str(e), _org_name)
            logger.exception(e)

    # default response
    # params
    repo_url = request.GET.get('repo', False)
    if not _org_name and (not repo_url or 'github.com' not in repo_url):
        return get_err_response(request, blank_img=(_org_name == 'Self'))

    try:
        # get avatar of repo
        if not _org_name:
            _org_name = org_name(repo_url)

        filepath = get_avatar(_org_name)
        if isinstance(filepath, JsonResponse):
            raise AvatarNotFoundException('no avatar found')
        # new image
        img = Image.new('RGBA', icon_size, (255, 255, 255))

        # execute
        avatar = Image.open(filepath, 'r').convert("RGBA")
        avatar = ImageOps.fit(avatar, icon_size, Image.ANTIALIAS)
        offset = 0, 0
        img.paste(avatar, offset, avatar)

        # Determine if we should add the Gitcoin logo
        if add_gitcoincologo and _org_name != 'gitcoinco':
            img = add_gitcoin_logo_blend(avatar, icon_size)

        response = HttpResponse(content_type='image/png')
        img.save(response, 'PNG')
        return response
    except AvatarNotFoundException:
        return get_err_response(request, blank_img=(_org_name == 'Self'))
    except (AttributeError, IOError, SyntaxError) as e:
        logger.error('Handle Avatar - Response error: (%s) - Handle: (%s)', str(e), _org_name)
        logger.exception(e)
        return get_err_response(request, blank_img=(_org_name == 'Self'))
예제 #3
0
 def handle(self, *args, **options):
     notifications = get_gh_notifications()
     print('Notifications Count: ', notifications.totalCount)
     for notification in notifications:
         if notification.reason == 'mention':
             try:
                 url = notification.subject.url
                 url = url.replace('/repos', '')
                 url = url.replace('//api.github', '//github')
                 latest_comment_url = notification.subject.latest_comment_url
                 _org_name = org_name(url)
                 _repo_name = repo_name(url)
                 _issue_number = issue_number(url)
                 _comment_id = latest_comment_url.split('/')[-1]
                 comment = get_issue_comments(_org_name, _repo_name,
                                              _issue_number, _comment_id)
                 does_mention_gitcoinbot = settings.GITHUB_API_USER in comment.get(
                     'body', '')
                 if comment.get('message', '') == "Not Found":
                     print("comment was not found")
                 elif not does_mention_gitcoinbot:
                     print("does not mention gitcoinbot")
                 else:
                     comment_from = comment['user']['login']
                     num_reactions = comment['reactions']['total_count']
                     print(_org_name, _repo_name, _issue_number,
                           _comment_id, num_reactions, comment_from)
                     is_from_gitcoinbot = settings.GITHUB_API_USER in comment_from
                     if num_reactions == 0 and not is_from_gitcoinbot:
                         print("unprocessed")
                         post_issue_comment_reaction(
                             _org_name, _repo_name, _comment_id, 'heart')
             except Exception as e:
                 logging.exception(e)
                 print(e)
예제 #4
0
def issue_details(request):
    """Determine the Github issue keywords of the specified Github issue or PR URL.

    Todo:
        * Modify the view to only use the Github API (remove BeautifulSoup).
        * Simplify the view logic.

    Returns:
        JsonResponse: A JSON response containing the Github issue or PR keywords.

    """
    from dashboard.utils import clean_bounty_url
    response = {}
    token = request.GET.get('token', None)
    url = request.GET.get('url')
    url_val = URLValidator()
    hackathon_slug = request.GET.get('hackathon_slug')
    duplicates = request.GET.get('duplicates', False)
    network = request.GET.get('network', 'mainnet')


    if hackathon_slug:
        sponsor_profiles = HackathonEvent.objects.filter(slug__iexact=hackathon_slug).prefetch_related('sponsor_profiles').values_list('sponsor_profiles__handle', flat=True)
        org_issue = org_name(url).lower()

        if org_issue not in sponsor_profiles:
            message = 'This issue is not under any sponsor repository'
            return JsonResponse({'status':'false','message':message}, status=404)

    if duplicates:
        if Bounty.objects.filter(github_url=url, network=network).exists():
            message = 'Bounty already exists for this github issue'
            response = {
                'status': 422,
                'message': message
            }
            return JsonResponse(response, status=422)

    try:
        url_val(url)
    except ValidationError:
        response['message'] = 'invalid arguments'
        return JsonResponse(response)

    if url.lower()[:19] != 'https://github.com/':
        response['message'] = 'invalid arguments'
        return JsonResponse(response)

    url_dict = get_url_dict(clean_bounty_url(url))

    try:
        if url_dict:
            response = get_gh_issue_details(token=token, **url_dict)
        else:
            response['message'] = 'could not parse Github url'
    except Exception as e:
        logger.warning(e)
        message = 'could not pull back remote response'
        return JsonResponse({'status':'false','message':message}, status=404)
    return JsonResponse(response)
예제 #5
0
 def handle(self, *args, **options):
     notifications = get_notifications()
     try:
         print('Notifications Count: ', notifications.totalCount)
         for notification in notifications:
             if hasattr(notification,
                        '_subject') and notification.reason == 'mention':
                 try:
                     url = notification.subject.url
                     url = url.replace('/repos', '')
                     url = url.replace('//api.github', '//github')
                     latest_comment_url = notification.subject.latest_comment_url
                     if latest_comment_url is None:
                         print("no latest comment url")
                         continue
                     _org_name = org_name(url)
                     _repo_name = repo_name(url)
                     _issue_number = issue_number(url)
                     if not latest_comment_url:
                         continue
                     _comment_id = latest_comment_url.split('/')[-1]
                     comment = get_issue_comments(_org_name, _repo_name,
                                                  _issue_number,
                                                  _comment_id)
                     does_mention_gitcoinbot = settings.GITHUB_API_USER in comment.body
                     if isinstance(comment, dict) and comment.get(
                             'message', '') == 'Not Found':
                         print("comment was not found")
                     elif not does_mention_gitcoinbot:
                         print("does not mention gitcoinbot")
                     else:
                         comment_from = comment.user.login
                         num_reactions = comment.get_reactions().totalCount
                         print(_org_name, _repo_name, _issue_number,
                               _comment_id, num_reactions, comment_from)
                         is_from_gitcoinbot = settings.GITHUB_API_USER in comment_from
                         if num_reactions == 0 and not is_from_gitcoinbot:
                             print("unprocessed")
                             post_issue_comment_reaction(
                                 _org_name, _repo_name, _comment_id,
                                 'heart')
                 except RateLimitExceededException as e:
                     logging.debug(e)
                     print(e)
                     time.sleep(60)
                 except Exception as e:
                     logging.exception(e)
                     print(e)
     except RateLimitExceededException as e:
         logging.debug(e)
         print(e)
     except AttributeError as e:
         logging.debug(e)
         print(e)
예제 #6
0
파일: views.py 프로젝트: nemani/web
def handle_avatar(request, _org_name='', add_gitcoincologo=False):
    from dashboard.models import Profile
    icon_size = (215, 215)

    if _org_name:
        try:
            profile = Profile.objects.select_related('avatar').get(
                handle__iexact=_org_name)
            if profile.avatar:
                if profile.avatar.use_github_avatar and profile.avatar.png:
                    return HttpResponse(profile.avatar.png.file,
                                        content_type='image/png')
                elif profile.avatar.svg and not profile.avatar.use_github_avatar:
                    return HttpResponse(profile.avatar.svg.file,
                                        content_type='image/svg+xml')
        except Exception as e:
            logger.error(e)

    # default response
    # params
    repo_url = request.GET.get('repo', False)
    if not _org_name and (not repo_url or 'github.com' not in repo_url):
        return get_err_response(request, blank_img=(_org_name == 'Self'))

    try:
        # get avatar of repo
        if not _org_name:
            _org_name = org_name(repo_url)

        filepath = get_avatar(_org_name)

        # new image
        img = Image.new('RGBA', icon_size, (255, 255, 255))

        # execute
        avatar = Image.open(filepath, 'r').convert("RGBA")
        avatar = ImageOps.fit(avatar, icon_size, Image.ANTIALIAS)
        offset = 0, 0
        img.paste(avatar, offset, avatar)

        # Determine if we should add the Gitcoin logo
        if add_gitcoincologo and _org_name != 'gitcoinco':
            img = add_gitcoin_logo_blend(avatar, icon_size)

        response = HttpResponse(content_type='image/png')
        img.save(response, 'PNG')
        return response
    except (AttributeError, IOError, SyntaxError) as e:
        logger.error(e)
        return get_err_response(request, blank_img=(_org_name == 'Self'))
예제 #7
0
def maybe_market_to_user_discord(bounty, event_name):
    """Send a Discord message to the user's discord channel for the specified Bounty.

    Args:
        bounty (dashboard.models.Bounty): The Bounty to be marketed.
        event_name (str): The name of the event.

    Returns:
        bool: Whether or not the Discord notification was sent successfully.

    """
    from dashboard.models import Profile
    if bounty.get_natural_value() < 0.0001:
        return False
    if bounty.network != settings.ENABLE_NOTIFICATIONS_ON_NETWORK:
        return False

    msg = build_message_for_integration(bounty, event_name)
    if not msg:
        return False

    url = bounty.github_url
    sent = False
    try:
        repo = org_name(url) + '/' + repo_name(url)
        subscribers = Profile.objects.filter(discord_repos__contains=[repo])
        subscribers = subscribers & Profile.objects.exclude(
            discord_webhook_url='')
        for subscriber in subscribers:
            try:
                headers = {'Content-Type': 'application/json'}
                body = {
                    "content": msg,
                    "avatar_url":
                    "https://gitcoin.co/static/v2/images/helmet.png"
                }
                discord_response = requests.post(
                    subscriber.discord_webhook_url, headers=headers, json=body)
                if discord_response.status_code == 204:
                    sent = True
            except Exception as e:
                print(e)
    except Exception as e:
        print(e)

    return sent
예제 #8
0
def maybe_market_to_user_slack(bounty, event_name):
    """Send a Slack message to the user's slack channel for the specified Bounty.

    Args:
        bounty (dashboard.models.Bounty): The Bounty to be marketed.
        event_name (str): The name of the event.

    Returns:
        bool: Whether or not the Slack notification was sent successfully.

    """
    from dashboard.models import Profile
    if bounty.get_natural_value() < 0.0001:
        return False
    if bounty.network != settings.ENABLE_NOTIFICATIONS_ON_NETWORK:
        return False

    msg = build_message_for_integration(bounty, event_name)
    if not msg:
        return False

    url = bounty.github_url
    sent = False
    try:
        repo = org_name(url) + '/' + repo_name(url)
        subscribers = Profile.objects.filter(slack_repos__contains=[repo])
        subscribers = subscribers & Profile.objects.exclude(slack_token='',
                                                            slack_channel='')
        for subscriber in subscribers:
            try:
                sc = SlackClient(subscriber.slack_token)
                sc.api_call(
                    "chat.postMessage",
                    channel=subscriber.slack_channel,
                    text=msg,
                    icon_url=settings.GITCOIN_SLACK_ICON_URL,
                )
                sent = True
            except Exception as e:
                print(e)
    except Exception as e:
        print(e)

    return sent
예제 #9
0
 def org_name(self):
     from git.utils import org_name
     try:
         return org_name(self.reference_url)
     except Exception:
         return None
예제 #10
0
 def test_org_name(self):
     """Test the github utility org_name method."""
     assert org_name(
         'https://github.com/gitcoinco/web/issues/1') == 'gitcoinco'
     assert org_name(
         'https://github.com/gitcoinco/web/issues/1/') == 'gitcoinco'
예제 #11
0
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")

    # Get maxAge GET param if provided, else default on the small side
    max_age = int(request.GET.get('maxAge', 3600))

    # params
    repo_url = request.GET.get('repo', False)
    if not repo_url or 'github.com' not in repo_url:
        return err_response

    try:
        badge = request.GET.get('badge', False)
        if badge:
            open_bounties = Bounty.objects.current() \
                .filter(
                    github_url__startswith=repo_url,
                    network='mainnet',
                    idx_status__in=['open']
                )

            tmpl = loader.get_template('svg_badge.txt')
            response = HttpResponse(
                tmpl.render({'bounties_count': open_bounties.count()}),
                content_type='image/svg+xml',
            )
            patch_response_headers(response, cache_timeout=max_age)
            return response

        # 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 hasattr(remote_user, 'avatar_url'):
                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")
        patch_response_headers(response, cache_timeout=max_age)
        return response
    except IOError as e:
        print(e)
        return err_response
예제 #12
0
 def github_avatar_url(self):
     """Return the local avatar URL."""
     _org_name = org_name(self.action_url)
     if _org_name:
         return f"{settings.BASE_URL}static/avatar/{_org_name}"
     return f"{settings.BASE_URL}funding/avatar?repo={self.github_url}&v=3"