Skip to content

Commit

Permalink
Add twitter verification for grants (#7367)
Browse files Browse the repository at this point in the history
* Add twitter verification for grants

* Update logic to display grant verified badge

* Fixes based on feedback

* Update security fro verify grants

* Fix attribute error

* Remove twitter sdk
  • Loading branch information
zoek1 authored Sep 14, 2020
1 parent 3014f62 commit 7118fae
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 13 deletions.
18 changes: 17 additions & 1 deletion app/assets/v2/css/grants/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,20 @@ h2.title {
padding-left: 10px;
}

}
}

.verification__warning {
background-color: #f8f8f0;
border: 2px solid #ffce08;
color: #b88b16;
font-weight: bold;
}

.verification__warning__icon {
font-size: 1.8rem;
margin-top: 7px;
}

.error {
color: var(--gc-pink);
}
2 changes: 1 addition & 1 deletion app/grants/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class GrantAdmin(GeneralAdmin):
'subscriptions_links', 'contributions_links', 'logo', 'logo_svg', 'image_css',
'link', 'clr_prediction_curve', 'hidden', 'grant_type', 'next_clr_calc_date', 'last_clr_calc_date',
'metadata', 'categories', 'twitter_handle_1', 'twitter_handle_2', 'view_count', 'is_clr_eligible', 'in_active_clrs',
'last_update', 'funding_info'
'last_update', 'funding_info', 'twitter_verified', 'twitter_verified_by', 'twitter_verified_at'
]
readonly_fields = [
'logo_svg_asset', 'logo_asset',
Expand Down
30 changes: 30 additions & 0 deletions app/grants/migrations/0078_auto_20200914_1945.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 2.2.4 on 2020-09-14 19:45

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('dashboard', '0148_add_brightid_status'),
('grants', '0077_grant_funding_info'),
]

operations = [
migrations.AddField(
model_name='grant',
name='twitter_verified',
field=models.BooleanField(default=False, help_text='The owner grant has verified the twitter account'),
),
migrations.AddField(
model_name='grant',
name='twitter_verified_at',
field=models.DateTimeField(blank=True, help_text='At what time and date what verified this grant', null=True),
),
migrations.AddField(
model_name='grant',
name='twitter_verified_by',
field=models.ForeignKey(blank=True, help_text='Team member who verified this grant', null=True, on_delete=django.db.models.deletion.SET_NULL, to='dashboard.Profile'),
),
]
3 changes: 3 additions & 0 deletions app/grants/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ class Meta:

# Grant Query Set used as manager.
objects = GrantQuerySet.as_manager()
twitter_verified = models.BooleanField(default=False, help_text='The owner grant has verified the twitter account')
twitter_verified_by = models.ForeignKey('dashboard.Profile', null=True, blank=True, on_delete=models.SET_NULL, help_text='Team member who verified this grant')
twitter_verified_at = models.DateTimeField(blank=True, null=True, help_text='At what time and date what verified this grant')

def __str__(self):
"""Return the string representation of a Grant."""
Expand Down
12 changes: 12 additions & 0 deletions app/grants/templates/grants/components/card.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
<div class="grant-item__content col-md-8 px-3">
<h2 class="grant-item__title font-subheader">
<a :href="grant.details_url">[[ grant.title.slice(0,60) ]][[ grant.title.length > 60 ? '...' : '']]</a>
<button v-if="grant.verified" class="btn btn-sm animate-verify p-0" data-container="body" data-toggle="popover" data-html="true" data-placement="bottom" data-trigger="click" data-content='
<p class="h6 my-2 text-left">Verified Ownership <img width="18" src="{% static "v2/images/badge-verify.svg" %}"></p>
<p>Grant owner has verified ownership of their twitter account.</p>
<a href="#">Learn more.</p>'
><img width="14" src="{% static 'v2/images/badge-verify.svg' %}" alt="">
</button>
</h2>
<div>
<p class="text-muted font-smaller-5 mb-0" style="height:2rem;" data-toggle="tooltip" data-placement="top" title="The last time the grant admin updated the grant." >
Expand Down Expand Up @@ -121,6 +127,12 @@ <h2 class="grant-item__title font-subheader">
<div class="grant-item__content px-3">
<h2 class="grant-item__title font-subheader">
<a :href="grant.details_url">[[ grant.title.slice(0,60) ]][[ grant.title.length > 60 ? '...' : '']]</a>
<button v-if="grant.verified" class="btn btn-sm animate-verify p-0" data-container="body" data-toggle="popover" data-html="true" data-placement="bottom" data-trigger="hover click" data-content='
<p class="h6 my-2 text-left">Verified Ownership <img width="18" src="{% static "v2/images/badge-verify.svg" %}"></p>
<p>Grant owner has verified ownership of their twitter account.</p>
<a href="#">Learn more.</p>'
><img width="16" src="{% static 'v2/images/badge-verify.svg' %}" alt="">
</button>
</h2>
<p class="grant-item__pitch font-caption mb-2">[[ grant.description.slice(0, 145) ]][[ grant.description.length > 145 ? '...' : '']]</p>
<p class="grant-item__pitch font-caption mb-0" style="height:2rem;" data-toggle="tooltip" data-placement="top" title="The last time the grant admin updated the grant." >
Expand Down
17 changes: 16 additions & 1 deletion app/grants/templates/grants/detail/funding.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,22 @@

{% load static humanize i18n grants_extra %}

<div class="px-0 pr-md-3">
<div class="px-0 pr-md-3 my-0 mx-0 mt-md-5 mr-md-5">
{% if not grant.twitter_verified %}
<div class="my-0 mx-0 mt-md-5 mr-md-5 py-2">
<div class="verification__warning py-2 px-2 d-flex">
<i class="fas fa-exclamation-triangle verification__warning__icon mr-2"></i>
<div>
<div class="uppercase">Warning: This grant has not verified their ownership of the property listed</div>
{% if is_team_member %}
<div class="text-right mt-3">
<button class="btn btn-sm btn-gc-blue" data-toggle="modal" data-target="#startVerification">Verify your grant</button>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div id="funding-card" class="card my-0 mx-0 mt-md-5 mr-md-5 shadow-sm">
<div class="card-body">
<div class="row progress-container {% if clr_active %} mb-2 {% endif %} {% if not is_team_member %} mt-4 {% endif %}">
Expand Down
74 changes: 71 additions & 3 deletions app/grants/templates/grants/detail/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,48 @@
{% include 'grants/detail/side-cart.html' %}
</div>
</div>
<div class="modal fade" id="startVerification" tabindex="-1" role="dialog" aria-labelledby="startVerification" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content text-center">
<div class="modal-header" style="border-bottom: none">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body px-5">
<img height="45" class="mb-4" src="{% static "v2/images/badge-verify.svg" %}" >
<h5 class="font-weight-bold mb-3">Verify Grant Ownership</h5>
<p class="mb-4">Verify your grant ownership to ensure that your supporters are contributing to the correct grant.</p>
<button id="triggerTwitter" class="btn btn-lg btn-gc-blue" data-toggle="modal" data-target="#startTwitterVerification">Verify with twitter</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="startTwitterVerification" tabindex="-1" role="dialog" aria-labelledby="startTwitterVerification" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content text-center">
<div class="modal-header" style="border-bottom: none">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body px-5">
<img height="45" class="mb-4" src="{% static "v2/images/badge-verify.svg" %}" >
<h5 class="font-weight-bold mb-3">Verify Grant Ownership with Twitter</h5>
<p class="mb-4 text-left"><b>Step 1:</b> Send a tweet from your account (<b>{{ grant.twitter_handle_1 }}</b>) saying <b>
{% with verification_tweet|add:" "|add:user_code as tweet %}
{{ tweet }} <a class="font-caption btn btn-outline-gc-blue btn-sm" href="https://twitter.com/intent/tweet?text={{ tweet|urlencode}}" target="_blank" ><i class="fab fa-twitter"></i> Tweet it</a></b> <br>
{% endwith %}
</p>
<p class="mb-4 text-left"><b>Step 2:</b>Click the "Verify" button below</p>
<button class="btn btn-lg btn-gc-blue mb-4" id="twitterVerification">Verify</button>
<br>
<span class="error" id="validation-errors"></span>

</div>
</div>
</div>
</div>
<input type="hidden" id="contract_version" name="contract_version" value="{{ grant.contract_version }}"/>
{% include 'shared/current_profile.html' %}
{% include 'shared/bottom_notification.html' %}
Expand All @@ -77,7 +119,6 @@
{% include 'shared/footer.html' %}
{% include 'grants/shared/shared_scripts.html' %}
</body>

{% include 'shared/activity_scripts.html' %}
<link rel="stylesheet" href="{% static "v2/css/activity_stream.css" %}">
<script src="{% static "v2/js/status.js" %}"></script>
Expand Down Expand Up @@ -121,8 +162,35 @@
<script type="text/javascript">
$(document).ready(function() {
$("img").unveil();
});

</script>
$('#twitterVerification').on('click', async () => {
const response = await fetchData('/grants/v1/api/{{grant.id}}/verify');

if (!response.ok) {
_alert(response.msg, 'error');
return;
}
if (response.verified) {
_alert('Congratulations, your grant is now verified!', 'success')
$('.verification__warning').remove();
$('#startTwitterVerification .close').click()
}

if (!response.has_text) {
$('#validation-errors').text(`Don't remove the intent "{{ verification_tweet }}"`);
return;
}

if (!response.has_code) {
$('#validation-errors').text(`Missing emoji code "{{ user_code }}", please don't remove this unique code before validate your grant.`);
return;
}
});


$('#triggerTwitter').on('click', async () => {
$("#startVerification .close").click();
});
});
</script>
</html>
6 changes: 6 additions & 0 deletions app/grants/templates/grants/detail/info.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ <h1 class="font-title-xl my-4 font-weight-bold">
<i style="width: 14px;" class="fab fa-twitter-square mr-2 text-center"></i>
<p class="d-inline-block mb-0">
<a href="https://twitter.com/{{grant.twitter_handle_1}}" target="new" rel="nofollow" data-toggle="tooltip" data-html="true" data-placement="top" title="Project Twitter Account">{{grant.twitter_handle_1}}</a>
<button class="btn btn-sm animate-verify {% if not grant.twitter_verified %}d-none{% endif %}" data-container="body" data-toggle="popover" data-html="true" data-placement="bottom" data-trigger="hover click" data-content='
<p class="h6 my-2 text-left">Verified Ownership <img width="18" src="{% static "v2/images/badge-verify.svg" %}"></p>
<p>Grant owner has verified ownership of their twitter account.</p>
<a href="#">Learn more.</p>'
><img width="18" src="{% static 'v2/images/badge-verify.svg' %}" alt="">
</button>
</p>
</div>
{% endif %}
Expand Down
4 changes: 2 additions & 2 deletions app/grants/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
bulk_fund, flag, get_grants, get_replaced_tx, grant_activity, grant_categories, grant_details, grant_fund,
grant_new, grant_new_whitelabel, grants, grants_addr_as_json, grants_bulk_add, grants_by_grant_type,
grants_cart_view, grants_clr, grants_stats_view, invoice, leaderboard, new_matching_partner, profile, quickstart,
subscription_cancel, toggle_grant_favorite, zksync_get_interrupt_status, zksync_set_interrupt_status,
subscription_cancel, toggle_grant_favorite, zksync_get_interrupt_status, zksync_set_interrupt_status, verify_grant,
)

app_name = 'grants'
Expand Down Expand Up @@ -65,5 +65,5 @@
path('<slug:grant_type>', grants_by_grant_type, name='grants_by_category2'),
path('<slug:grant_type>/', grants_by_grant_type, name='grants_by_category'),
path('v1/api/clr', grants_clr, name='grants_clr'),

path('v1/api/<int:grant_id>/verify', verify_grant, name='verify_grant')
]
17 changes: 15 additions & 2 deletions app/grants/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import logging
import os
from decimal import Decimal
from random import random, randint, seed
from secrets import token_hex

from economy.utils import ConversionRateNotFoundError, convert_amount
Expand All @@ -28,6 +29,10 @@

logger = logging.getLogger(__name__)

block_codes = ['▖', '▗', '▘', '▙', '▚', '▛', '▜', '▝', '▞', '▟']
emoji_codes = ['🎉', '🎈', '🎁', '🎊', '🙌', '🥂', '🎆', '🔥', '⚡', '👍']


def get_upload_filename(instance, filename):
salt = token_hex(16)
file_path = os.path.basename(filename)
Expand Down Expand Up @@ -115,10 +120,10 @@ def which_clr_round(timestamp):

if round_start < timestamp < round_end:
return round

return None

def get_converted_amount(amount, token_symbol):
def get_converted_amount(amount, token_symbol):
try:
if token_symbol == "ETH" or token_symbol == "WETH":
return Decimal(float(amount) * float(eth_usd_conv_rate()))
Expand All @@ -142,3 +147,11 @@ def get_converted_amount(amount, token_symbol):
except ConversionRateNotFoundError as no_conversion_e:
logger.info(no_conversion_e)
return None


def get_user_code(user_id, grant, coding_set=block_codes, length=6):
seed(user_id ** grant.id)
coding_id = [coding_set[randint(0, 9)] for _ in range(length)]

return ''.join(coding_id)

Loading

0 comments on commit 7118fae

Please sign in to comment.