Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add twitter verification for grants #7367

Merged
merged 7 commits into from
Sep 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ could we reduce the overall size of this to make it look neater ? It looks very big on the screenshot

<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 = ['🎉', '🎈', '🎁', '🎊', '🙌', '🥂', '🎆', '🔥', '⚡', '👍']
thelostone-mc marked this conversation as resolved.
Show resolved Hide resolved


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