Skip to content

Commit

Permalink
Merge branch 'stable'
Browse files Browse the repository at this point in the history
  • Loading branch information
chibie committed Aug 15, 2022
2 parents 70f4271 + 8210cb4 commit 63cbf23
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 12 deletions.
7 changes: 5 additions & 2 deletions app/assets/v2/js/grants/_new.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,8 @@ if (document.getElementById('gc-new-grant')) {
return this.submitted && this.step === this.currentSteps.length && Object.keys(this.errors).length === 0;
},
grantTagOptions() {
const sorted_tags = this.grant_tags.sort((a, b) => a.id - b.id);
const next_id = sorted_tags[sorted_tags.length-1].id + 1;
const all_tags = this.grant_tags.sort((a, b) => b.is_eligibility_tag - a.is_eligibility_tag);
const first_discovery = (tag) => tag.is_eligibility_tag === 0;

Expand All @@ -490,12 +492,13 @@ if (document.getElementById('gc-new-grant')) {
name: 'eligibility tags'.toUpperCase(),
is_eligibility_tag: 'label'
});

all_tags.splice(all_tags.findIndex(first_discovery), 0, {
id: all_tags.length + 1,
id: next_id,
name: 'discovery tags'.toUpperCase(),
is_eligibility_tag: 'label'
});

return all_tags;
},
queryParams() {
Expand Down
25 changes: 25 additions & 0 deletions app/dashboard/management/commands/add_main_rnd_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.core.management.base import BaseCommand

from grants.models import Grant, GrantTag

class Command(BaseCommand):

help = 'updates all approved grants to include the main-round tag'

def handle(self, *args, **options):
# main-round tag
tag = GrantTag.objects.get(pk=62)
grants = Grant.objects.filter(active=True, hidden=False, is_clr_eligible=True)

print(f"adding main-round tag to {grants.count()} Grants:")

# for every eligible grant
for grant in grants:
try:
# update the tag record to include the main round tag
grant.tags.add(tag)
grant.save()
except Exception as e:
pass

print("\n - done\n")
9 changes: 5 additions & 4 deletions app/grants/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class FlagAdmin(admin.ModelAdmin):
ordering = ['-id']
raw_id_fields = ['profile', 'grant']
readonly_fields = ['grant_link']

def grant_link(self, obj):
return format_html("<a href='/grants/{id}/{slug}' target=\"_blank\">Grant Details</a>", id=obj.grant.id, slug=obj.grant.slug)

Expand Down Expand Up @@ -105,9 +105,10 @@ class GrantAdmin(GeneralAdmin):
'title', 'is_grant_idle',
'active', 'visible', 'is_clr_eligible',
'migrated_to', 'region',
'grant_type', 'tags', 'tag_eligibility_reason','description', 'description_rich', 'github_project_url', 'reference_url', 'admin_address',
'amount_received', 'amount_received_in_round', 'monthly_amount_subscribed', 'defer_clr_to',
'deploy_tx_id', 'cancel_tx_id', 'admin_profile', 'token_symbol',
'grant_type', 'tags_requested', 'tags', 'tag_eligibility_reason',
'description', 'description_rich', 'github_project_url', 'reference_url',
'admin_address', 'amount_received', 'amount_received_in_round', 'monthly_amount_subscribed',
'defer_clr_to', 'deploy_tx_id', 'cancel_tx_id', 'admin_profile', 'token_symbol',
'token_address', 'contract_address', 'contract_version', 'network', 'required_gas_price', 'logo_svg_asset',
'logo_asset', 'created_on', 'modified_on', 'team_member_list',
'subscriptions_links', 'contributions_links', 'logo', 'logo_svg', 'image_css',
Expand Down
23 changes: 23 additions & 0 deletions app/grants/migrations/0146_auto_20220809_1134.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 2.2.24 on 2022-08-09 11:34

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('grants', '0145_grant_tag_eligibility_reason'),
]

operations = [
migrations.AddField(
model_name='grant',
name='tags_requested',
field=models.ManyToManyField(blank=True, related_name='tags_requested', to='grants.GrantTag'),
),
migrations.AlterField(
model_name='grant',
name='tags',
field=models.ManyToManyField(blank=True, related_name='tags', to='grants.GrantTag'),
),
]
3 changes: 2 additions & 1 deletion app/grants/models/grant.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ class Meta:
db_index=True,
)
categories = models.ManyToManyField('GrantCategory', blank=True) # TODO: REMOVE
tags = models.ManyToManyField('GrantTag', blank=True)
tags = models.ManyToManyField('GrantTag', blank=True, related_name='tags')
tags_requested = models.ManyToManyField('GrantTag', blank=True, related_name='tags_requested')
tag_eligibility_reason = models.TextField(default='', blank=True, help_text=_('Eligibility Tag Reasoning'))
twitter_handle_1 = models.CharField(default='', max_length=255, help_text=_('Grants twitter handle'), blank=True)
twitter_handle_2 = models.CharField(default='', max_length=255, help_text=_('Grants twitter handle'), blank=True)
Expand Down
4 changes: 4 additions & 0 deletions app/grants/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
leaderboard, manage_ethereum_cart_data, matching_funds, profile, remove_grant_from_collection, save_collection,
toggle_grant_favorite, upload_sybil_csv, verify_grant,
)
from grants.views_api_vc import contributor_statistics, grantee_statistics

app_name = 'grants/'
urlpatterns = [
Expand Down Expand Up @@ -126,4 +127,7 @@
path('v1/api/upload_sybil_csv', upload_sybil_csv, name='upload_sybil_csv'),
path('v1/api/ingest_merkle_claim_to_clr_match', ingest_merkle_claim_to_clr_match, name='ingest_merkle_claim_to_clr_match'),

# VC verification API (when issuing a VC)
path('v1/api/vc/contributor_statistics', contributor_statistics, name='contributor_statistics'),
path('v1/api/vc/grantee_statistics', grantee_statistics, name='grantee_statistics'),
]
6 changes: 3 additions & 3 deletions app/grants/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ def save_grant_to_notion(grant):
# fully qualified url
fullUrl = BASE_URL.rstrip('/') + grant.url
grant_tags = []
for tag in grant.tags.all():
for tag in grant.tags_requested.all():
grant_tags.append(str(tag))

# write to NOTION_SYBIL_DB following the defined schema (returns dict of new object)
Expand Down Expand Up @@ -494,10 +494,10 @@ def bsci_script(csv: str) -> tuple:
# Assign final `is_sybil` markings according to a priorization criteria
df.loc[labels_by_evaluation, 'is_sybil'] = df[labels_by_evaluation].evaluation_score > EVAL_THRESHOLD
df.loc[labels_by_evaluation, 'label'] = "Human Evaluation"

df.loc[labels_by_heuristic, 'is_sybil'] = df[labels_by_heuristic].heuristic_score > HEURISTIC_THRESHOLD
df.loc[labels_by_heuristic, 'label'] = "Heuristics"

df.loc[labels_by_prediction, 'is_sybil'] = df[labels_by_prediction].prediction_score > ML_THRESHOLD
df.loc[labels_by_prediction, 'label'] = "ML Prediction"

Expand Down
2 changes: 1 addition & 1 deletion app/grants/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3347,7 +3347,7 @@ def post(self, request):
for tag_id in tag_ids:
try:
tag = GrantTag.objects.get(pk=tag_id)
grant.tags.add(tag)
grant.tags_requested.add(tag)
except Exception as e:
pass

Expand Down
202 changes: 202 additions & 0 deletions app/grants/views_api_vc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# -*- coding: utf-8 -*-
"""Define the Grant views for API used by the passport IAM
Copyright (C) 2021 Gitcoin Core
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import logging

from django.conf import settings
from django.db.models import Sum
from django.http import JsonResponse
from django.utils.translation import gettext_lazy as _

from grants.models import Contribution, Grant
from perftools.models import StaticJsonEnv
from townsquare.models import SquelchProfile

logger = logging.getLogger(__name__)


def ami_api_token_required(func):
def decorator(request, *args, **kwargs):
try:
apiToken = StaticJsonEnv.objects.get(key="AMI_API_TOKEN")
expectedToken = apiToken.data["token"]
receivedToken = request.headers.get("Authorization")

if receivedToken:
# Token shall look like "token <bearer token>", and we need only the <bearer token> part
receivedToken = receivedToken.split(" ")[1]

if expectedToken == receivedToken:
return func(request, *args, **kwargs)
else:
return JsonResponse(
{
"error": "Access denied",
},
status=403,
)
except Exception as e:
logger.error("Error in ami_api_token_required %s", e)
return JsonResponse(
{
"error": "An unexpected error occured",
},
status=500,
)

return decorator


@ami_api_token_required
def contributor_statistics(request):
handle = request.GET.get("handle")

if not handle:
return JsonResponse(
{"error": "Bad request, 'handle' parameter is missing or invalid"},
status=400,
)

# Get number of grants the user contributed to
num_grants_contribute_to = (
Contribution.objects.filter(profile_for_clr__handle=handle, success=True)
.order_by("grant_id")
.distinct("grant_id")
.count()
)

# Get the number of grants the user contributed to
num_rounds_contribute_to = (
Contribution.objects.filter(
success=True,
subscription__contributor_profile__handle=handle,
subscription__network="mainnet",
subscription__grant__clr_calculations__latest=True,
)
.order_by("subscription__grant__clr_calculations__grantclr__round_num")
.distinct("subscription__grant__clr_calculations__grantclr__round_num")
.count()
)

total_contribution_amount = Contribution.objects.filter(
profile_for_clr__handle=handle, success=True
).aggregate(Sum("amount_per_period_usdt"))["amount_per_period_usdt__sum"]
total_contribution_amount = (
total_contribution_amount if total_contribution_amount is not None else 0
)

# GR14 contributor (and not squelched by FDD)
profile_squelch = SquelchProfile.objects.filter(
profile__handle=handle, active=True
).values_list("profile_id", flat=True)

num_gr14_contributions = (
Contribution.objects.filter(
success=True,
subscription__contributor_profile__handle=handle,
subscription__network="mainnet",
subscription__grant__clr_calculations__latest=True,
subscription__grant__clr_calculations__grantclr__round_num=14,
)
.exclude(subscription__contributor_profile_id__in=profile_squelch)
.count()
)

return JsonResponse(
{
"num_grants_contribute_to": num_grants_contribute_to,
"num_rounds_contribute_to": num_rounds_contribute_to,
"total_contribution_amount": total_contribution_amount,
"is_gr14_contributor": num_gr14_contributions > 0,
}
)


@ami_api_token_required
def grantee_statistics(request):
handle = request.GET.get("handle")

if not handle:
return JsonResponse(
{"error": "Bad request, 'handle' parameter is missing or invalid"},
status=400,
)

# Get number of owned grants
num_owned_grants = Grant.objects.filter(
admin_profile__handle=handle,
hidden=False,
active=True,
is_clr_eligible=True,
).count()

# Get the total amount of contrinutors for ane users grants that where not squelched and are not the owner himself
all_squelched = SquelchProfile.objects.filter(active=True).values_list(
"profile_id", flat=True
)
num_grant_contributors = (
Contribution.objects.filter(
success=True,
subscription__network="mainnet",
subscription__grant__hidden=False,
subscription__grant__active=True,
subscription__grant__is_clr_eligible=True,
subscription__grant__admin_profile__handle=handle,
)
.exclude(subscription__contributor_profile_id__in=all_squelched)
.exclude(subscription__contributor_profile__handle=handle)
.order_by("subscription__contributor_profile_id")
.distinct("subscription__contributor_profile_id")
.count()
)

# Get the total amount of contributions received by the owned grants (excluding the contributions made by the owner)
total_contribution_amount = (
Contribution.objects.filter(
success=True,
subscription__network="mainnet",
subscription__grant__hidden=False,
subscription__grant__active=True,
subscription__grant__is_clr_eligible=True,
subscription__grant__admin_profile__handle=handle,
)
.exclude(subscription__contributor_profile__handle=handle)
.aggregate(Sum("amount_per_period_usdt"))["amount_per_period_usdt__sum"]
)
total_contribution_amount = (
total_contribution_amount if total_contribution_amount is not None else 0
)

# [IAM] As an IAM server, I want to issue stamps for grant owners whose project have tagged matching-eligibel in an eco-system and/or cause round
num_grants_in_eco_and_cause_rounds = Grant.objects.filter(
admin_profile__handle=handle,
hidden=False,
active=True,
is_clr_eligible=True,
clr_calculations__grantclr__type__in=["ecosystem", "cause"],
).count()

return JsonResponse(
{
"num_owned_grants": num_owned_grants,
"num_grant_contributors": num_grant_contributors,
"num_grants_in_eco_and_cause_rounds": num_grants_in_eco_and_cause_rounds,
"total_contribution_amount": total_contribution_amount,
}
)
2 changes: 1 addition & 1 deletion docker-compose-celery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:
max-file: '10'
driver: json-file

image: gitcoin/web:a68541e6fe
image: gitcoin/web:0b8eae8cd2

volumes:
# - .:/code
Expand Down

0 comments on commit 63cbf23

Please sign in to comment.