diff --git a/app/assets/v2/js/grants/new_match.js b/app/assets/v2/js/grants/new_match.js
new file mode 100644
index 00000000000..454ff6aca81
--- /dev/null
+++ b/app/assets/v2/js/grants/new_match.js
@@ -0,0 +1,217 @@
+Vue.component('v-select', VueSelect.VueSelect);
+
+
+Vue.mixin({
+ methods: {
+ clearForm: function() {
+ let vm = this;
+
+ vm.form = {
+ why: '',
+ amount: 0,
+ stage: '',
+ grant_types: [],
+ grant_categories: [],
+ grant_collections: [],
+ anonymous: false,
+ comment: '',
+ tx_id: ''
+ };
+
+ },
+ transfer_web3: function(params) {
+ let vm = this;
+
+ const amount = params.amount;
+ const decimals = 18;
+ const to = '0xde21F729137C5Af1b01d73aF1dC21eFfa2B8a0d6';
+ // const token_addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
+ const token_addr = (document.web3network == 'mainnet') ?
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F' :
+ '0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa'
+
+ ;
+ const amountInWei = amount * 1.0 * Math.pow(10, decimals);
+ const amountAsString = new web3.utils.BN(BigInt(amountInWei)).toString();
+
+ const token_contract = new web3.eth.Contract(token_abi, token_addr);
+
+ return token_contract.methods.transfer(to, web3.utils.toHex(amountAsString))
+ .send({from: selectedAccount},
+ (error, tx_id) => {
+ if (error) {
+ _alert({ message: gettext('Unable to pay the match pledge amount. Please try again.') }, 'error');
+ console.error(`error: unable to pay pledge due to : ${error}`);
+ return;
+ }
+ params['tx_id'] = tx_id;
+ console.log(params);
+ vm.submitted = true;
+ vm.createMatchingPledge(params);
+
+ }
+ );
+ },
+ checkForm: function(e) {
+ let vm = this;
+
+ vm.submitted = true;
+ vm.errors = {};
+ if (!vm.form.why.length) {
+ vm.$set(vm.errors, 'why', 'Please select why you want to create a match pledge');
+ }
+ if (!vm.form.amount) {
+ vm.$set(vm.errors, 'amount', 'Please enter amount you would want to pledge');
+ }
+ if (!vm.form.stage) {
+ vm.$set(vm.errors, 'stage', 'Please select the stage of funding');
+ }
+
+ if (!vm.grants_to_fund) {
+ vm.$set(vm.errors, 'grants_to_fund', 'Please select one of the options');
+ } else if (vm.grants_to_fund == 'types' && !vm.form.grant_types.length > 0) {
+ vm.$set(vm.errors, 'grant_types', 'Please select the grant types');
+ } else if (vm.grants_to_fund == 'collections' && !vm.form.grant_collections.length > 0) {
+ vm.$set(vm.errors, 'grant_collections', 'Please select the collections');
+ }
+
+
+ if (Object.keys(vm.errors).length) {
+ return false; // there are errors the user must correct
+ }
+ vm.submitted = false;
+ return true; // no errors, continue to create match pledge
+ },
+ submitForm: async function(event) {
+ event.preventDefault();
+ let vm = this;
+ let form = vm.form;
+
+ // Exit if form is not valid
+ if (!vm.checkForm(event))
+ return;
+
+ if (vm.grants_to_fund == 'types') {
+ vm.form.grant_collections = [];
+ } else if (vm.grants_to_fund == 'collections') {
+ vm.form.grant_types = [];
+ vm.form.grant_categories = [];
+ }
+
+ const params = {
+ 'why': form.why,
+ 'amount': form.amount,
+ 'stage': form.stage,
+ 'grant_types[]': form.grant_types.join(),
+ 'grant_categories[]': form.grant_categories.join(),
+ 'grant_collections[]': form.grant_collections.join(),
+ 'anonymous': form.anonymous,
+ 'comment': form.comment
+ };
+
+ if (form.stage == 'ready') {
+ if (!provider) {
+ onConnect();
+ return false;
+ }
+
+ vm.transfer_web3(params);
+ } else {
+ vm.submitted = true;
+ vm.createMatchingPledge(params);
+ }
+
+ },
+ async createMatchingPledge(data) {
+ let vm = this;
+
+ if (typeof ga !== 'undefined') {
+ ga('send', 'event', 'Create Match Pledge', 'click', 'Grant Match Pledge Creator');
+ }
+
+
+ try {
+ const url = '/grants/v1/api/matching-pledge/create';
+
+ const headers = {
+ 'X-CSRFToken': $("input[name='csrfmiddlewaretoken']").val()
+ };
+
+ response = await fetchData(url, 'POST', data, headers);
+
+ if (response.status == 200) {
+ _alert('Match Pledge Request Created.');
+ vm.clearForm();
+ } else {
+ vm.submitted = false;
+ _alert('Unable to create matching pledge. Please try again', 'error');
+ console.error(`error: match pledge creation failed with status: ${response.status} and message: ${response.message}`);
+ }
+
+ } catch (err) {
+ vm.submitted = false;
+ _alert('Unable to create matching pledge. Please try again', 'error');
+ console.error(`error: match pledge creation failed with msg ${err}`);
+ }
+ }
+ },
+ watch: {
+ deep: true,
+ form: {
+ deep: true,
+ handler(newVal, oldVal) {
+ if (this.dirty && this.submitted) {
+ this.checkForm();
+ }
+ this.dirty = true;
+ }
+ }
+ }
+});
+
+if (document.getElementById('gc-new-match')) {
+
+ const why_options = [
+ 'to see an ecosystem grow',
+ 'to give back',
+ 'to support a marketing campaign',
+ 'all of the above',
+ 'other'
+ ];
+ const stage_options = [
+ {'key': 'ready', 'val': 'I am ready to transfer DAI'},
+ {'key': 'details', 'val': 'Send me more details'}
+ ];
+
+ appFormBounty = new Vue({
+ delimiters: [ '[[', ']]' ],
+ el: '#gc-new-match',
+ components: {
+ 'vue-select': 'vue-select'
+ },
+ data() {
+ return {
+ grants_to_fund: 'types',
+ grant_types: document.grant_types,
+ grant_collections: document.grant_collections,
+ grant_categories: document.grant_categories,
+ why_options: why_options,
+ stage_options: stage_options,
+ network: 'mainnet',
+ submitted: false,
+ errors: {},
+ form: {
+ why: '',
+ amount: 0,
+ stage: '',
+ grant_types: [],
+ grant_categories: [],
+ grant_collections: [],
+ anonymous: false,
+ comment: '',
+ tx_id: ''
+ }
+ };
+ }
+ });
+}
diff --git a/app/assets/v2/js/grants/newmatch.js b/app/assets/v2/js/grants/newmatch.js
deleted file mode 100644
index 64f26d3dfcc..00000000000
--- a/app/assets/v2/js/grants/newmatch.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* eslint-disable no-console */
-$(document).ready(function() {
- $('#input-categories').select2();
-});
diff --git a/app/grants/clr.py b/app/grants/clr.py
index f36647a03dd..f9465b674f0 100644
--- a/app/grants/clr.py
+++ b/app/grants/clr.py
@@ -29,7 +29,7 @@
import numpy as np
import pytz
-from grants.models import Contribution, Grant, PhantomFunding
+from grants.models import Contribution, Grant, GrantCollection
from marketing.models import Stat
from perftools.models import JSONStore
@@ -163,7 +163,7 @@ def calculate_clr(aggregated_contributions, pair_totals, trust_dict, v_threshold
bigtot = 0
totals = []
-
+
for proj, contribz in aggregated_contributions.items():
tot = 0
_num = 0
@@ -282,7 +282,6 @@ def calculate_clr_for_donation(grant, amount, grant_contributions_curr, total_po
Returns:
contributions : contributions data object
grants : list of grants based on clr_type
- phantom_funding_profiles : phantom funding data object
'''
def fetch_data(clr_round, network='mainnet'):
@@ -291,17 +290,23 @@ def fetch_data(clr_round, network='mainnet'):
clr_end_date = clr_round.end_date
grant_filters = clr_round.grant_filters
subscription_filters = clr_round.subscription_filters
+ collection_filters = clr_round.collection_filters
contributions = Contribution.objects.prefetch_related('subscription', 'profile_for_clr').filter(match=True, created_on__gte=clr_start_date, created_on__lte=clr_end_date, success=True).nocache()
if subscription_filters:
contributions = contributions.filter(**subscription_filters)
grants = Grant.objects.filter(network=network, hidden=False, active=True, is_clr_eligible=True, link_to_new_grant=None)
- grants = grants.filter(**grant_filters)
- phantom_funding_profiles = PhantomFunding.objects.filter(created_on__gte=clr_start_date, created_on__lte=clr_end_date)
+ if grant_filters:
+ # Grant Filters (grant_type, category)
+ grants = grants.filter(**grant_filters)
+ elif collection_filters:
+ # Collection Filters
+ grant_ids = GrantCollection.objects.filter(**collection_filters).values_list('grants', flat=True)
+ grants = grants.filter(pk__in=grant_ids)
- return grants, contributions, phantom_funding_profiles
+ return grants, contributions
@@ -311,7 +316,6 @@ def fetch_data(clr_round, network='mainnet'):
Args:
grants : grants list
contributions : contributions list for thoe grants
- phantom_funding_profiles: phantom funding for those grants
clr_round : GrantCLR
Returns:
@@ -321,7 +325,7 @@ def fetch_data(clr_round, network='mainnet'):
}
'''
-def populate_data_for_clr(grants, contributions, phantom_funding_profiles, clr_round):
+def populate_data_for_clr(grants, contributions, clr_round):
contrib_data_list = []
@@ -377,13 +381,13 @@ def predict_clr(save_to_db=False, from_date=None, clr_round=None, network='mainn
v_threshold = float(clr_round.verified_threshold)
uv_threshold = float(clr_round.unverified_threshold)
- grants, contributions, phantom_funding_profiles = fetch_data(clr_round, network)
+ grants, contributions = fetch_data(clr_round, network)
if contributions.count() == 0:
print(f'No Contributions for CLR {clr_round.round_num}. Exiting')
return
- grant_contributions_curr = populate_data_for_clr(grants, contributions, phantom_funding_profiles, clr_round)
+ grant_contributions_curr = populate_data_for_clr(grants, contributions, clr_round)
if only_grant_pk:
grants = grants.filter(pk=only_grant_pk)
diff --git a/app/grants/migrations/0092_auto_20201105_0831.py b/app/grants/migrations/0092_auto_20201105_0831.py
new file mode 100644
index 00000000000..8cfd11773bd
--- /dev/null
+++ b/app/grants/migrations/0092_auto_20201105_0831.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.2.4 on 2020-11-05 08:31
+
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('grants', '0091_contribution_anonymous'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='grantclr',
+ name='collection_filters',
+ field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, help_text='Grant Collections to be allowed in this CLR round', null=True),
+ ),
+ migrations.AddField(
+ model_name='granttype',
+ name='is_active',
+ field=models.BooleanField(db_index=True, default=True, help_text='Is Grant Type currently active'),
+ ),
+ migrations.AlterField(
+ model_name='matchpledge',
+ name='pledge_type',
+ field=models.CharField(blank=True, choices=[('tech', 'tech'), ('media', 'media'), ('health', 'health'), ('change', 'change')], help_text='CLR pledge type', max_length=15, null=True),
+ ),
+ ]
diff --git a/app/grants/models.py b/app/grants/models.py
index ae381de7ef3..9676c8923bb 100644
--- a/app/grants/models.py
+++ b/app/grants/models.py
@@ -95,6 +95,7 @@ class GrantType(SuperModel):
name = models.CharField(unique=True, max_length=15, help_text="Grant Type")
label = models.CharField(max_length=25, null=True, help_text="Display Name")
+ is_active = models.BooleanField(default=True, db_index=True, help_text="Is Grant Type currently active")
categories = models.ManyToManyField(
GrantCategory,
help_text="Grant Categories associated with Grant Type"
@@ -140,6 +141,11 @@ class GrantCLR(SuperModel):
null=True, blank=True,
help_text="Grant Subscription to be allowed in this CLR round"
)
+ collection_filters = JSONField(
+ default=dict,
+ null=True, blank=True,
+ help_text="Grant Collections to be allowed in this CLR round"
+ )
verified_threshold = models.DecimalField(help_text="Verfied CLR Threshold",
default=25.0,
decimal_places=2,
@@ -161,7 +167,6 @@ class GrantCLR(SuperModel):
decimal_places=4,
max_digits=10,
)
-
logo = models.ImageField(
upload_to=get_upload_filename,
null=True,
@@ -1823,7 +1828,7 @@ class MatchPledge(SuperModel):
max_digits=50,
help_text=_('The matching pledge amount in DAI.'),
)
- pledge_type = models.CharField(max_length=15, choices=PLEDGE_TYPES, default='tech', help_text=_('CLR pledge type'))
+ pledge_type = models.CharField(max_length=15, null=True, blank=True, choices=PLEDGE_TYPES, help_text=_('CLR pledge type'))
comments = models.TextField(default='', blank=True, help_text=_('The comments.'))
end_date = models.DateTimeField(null=False, default=next_month)
data = JSONField(null=True, blank=True)
diff --git a/app/grants/templates/grants/new_match.html b/app/grants/templates/grants/new_match.html
new file mode 100644
index 00000000000..32cdb23233c
--- /dev/null
+++ b/app/grants/templates/grants/new_match.html
@@ -0,0 +1,246 @@
+{% comment %}
+ Copyright (C) 2020 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
- {% trans "Thank you for your interest in supporting public goods." %}
-
- {% trans "on Gitcoin. Complete the form below to get started." %}
-