From 3db853a45ddaaa362e26d7de5abf50672dd15cd2 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Wed, 5 Jun 2019 23:00:27 -0300 Subject: [PATCH 01/38] begining of dashboard --- app/app/settings.py | 3 +- app/app/urls.py | 5 +- app/board/__init__.py | 0 app/board/admin.py | 3 ++ app/board/apps.py | 5 ++ app/board/migrations/__init__.py | 0 app/board/models.py | 3 ++ app/board/templates/board.html | 47 ++++++++++++++++++ app/board/tests.py | 3 ++ app/board/urls.py | 29 +++++++++++ app/board/views.py | 83 ++++++++++++++++++++++++++++++++ app/dashboard/models.py | 9 ++-- 12 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 app/board/__init__.py create mode 100644 app/board/admin.py create mode 100644 app/board/apps.py create mode 100644 app/board/migrations/__init__.py create mode 100644 app/board/models.py create mode 100644 app/board/templates/board.html create mode 100644 app/board/tests.py create mode 100644 app/board/urls.py create mode 100644 app/board/views.py diff --git a/app/app/settings.py b/app/app/settings.py index de188a6de1d..e0392b74a2f 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -113,6 +113,7 @@ 'revenue', 'event_ethdenver2019', 'inbox', + 'board', ] MIDDLEWARE = [ @@ -142,7 +143,7 @@ TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': ['retail/templates/', 'dataviz/templates', 'kudos/templates', 'inbox/templates'], + 'DIRS': ['retail/templates/', 'dataviz/templates', 'kudos/templates', 'inbox/templates', 'board/templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/app/app/urls.py b/app/app/urls.py index be7628f9fba..6ee039a646d 100644 --- a/app/app/urls.py +++ b/app/app/urls.py @@ -64,6 +64,9 @@ # inbox path('inbox/', include('inbox.urls', namespace='inbox')), + # board + path('dashboard/', include('board.urls', namespace='board')), + # kudos path('kudos/', kudos.views.about, name='kudos_main'), path('kudos/about/', kudos.views.about, name='kudos_about'), @@ -124,7 +127,7 @@ re_path(r'^onboard/(?P\w+)/$', dashboard.views.onboard, name='onboard'), re_path(r'^onboard/contributor/avatar/?$', dashboard.views.onboard_avatar, name='onboard_avatar'), url(r'^postcomment/', dashboard.views.post_comment, name='post_comment'), - url(r'^dashboard/?', dashboard.views.dashboard, name='dashboard'), + # url(r'^dashboard/?', dashboard.views.dashboard, name='dashboard'), url(r'^explorer/?', dashboard.views.dashboard, name='explorer'), url(r'^hackathon/ethhack2019', dashboard.views.ethhack, name='ethhack_2019'), path('revenue/attestations/new', revenue.views.new_attestation, name='revenue_new_attestation'), diff --git a/app/board/__init__.py b/app/board/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/board/admin.py b/app/board/admin.py new file mode 100644 index 00000000000..8c38f3f3dad --- /dev/null +++ b/app/board/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/board/apps.py b/app/board/apps.py new file mode 100644 index 00000000000..a943e308fb9 --- /dev/null +++ b/app/board/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class BoardConfig(AppConfig): + name = 'board' diff --git a/app/board/migrations/__init__.py b/app/board/migrations/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/board/models.py b/app/board/models.py new file mode 100644 index 00000000000..71a83623907 --- /dev/null +++ b/app/board/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/app/board/templates/board.html b/app/board/templates/board.html new file mode 100644 index 00000000000..394042d649c --- /dev/null +++ b/app/board/templates/board.html @@ -0,0 +1,47 @@ +{% comment %} + Copyright (C) 2019 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 + . +{% endcomment %} +{% load i18n static add_url_schema avatar_tags %} + + + + + {% include 'shared/head.html' %} + {% include 'shared/cards.html' %} + + + {% include 'shared/top_nav.html' with class='d-md-flex' %} + {% include 'shared/nav.html' %} +
+ + + + +
+
+ +
+ {% include 'shared/footer.html' %} + {% include 'shared/analytics.html' %} + {% include 'shared/footer_scripts.html' with slim=1 %} + + + + + diff --git a/app/board/tests.py b/app/board/tests.py new file mode 100644 index 00000000000..7ce503c2dd9 --- /dev/null +++ b/app/board/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/board/urls.py b/app/board/urls.py new file mode 100644 index 00000000000..97d199f5e5d --- /dev/null +++ b/app/board/urls.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +"""Define url for the inbox app. + +Copyright (C) 2019 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 . + +""" + +from django.urls import path + +from board import views + +app_name = 'board' +urlpatterns = [ + path('', views.board, name='board_view'), + path('api/v0.1/get_bounties/', views.get_bounties, name='get_bounties'), +] diff --git a/app/board/views.py b/app/board/views.py new file mode 100644 index 00000000000..053ff3d6d8d --- /dev/null +++ b/app/board/views.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +"""Define view for the inbox app. + +Copyright (C) 2019 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 . + +""" + +import json + +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.contrib.staticfiles.templatetags.staticfiles import static +from django.core.paginator import Paginator +from django.http import HttpResponse, JsonResponse +from django.template.response import TemplateResponse +from django.utils.translation import gettext_lazy as _ +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_GET, require_http_methods + +from dashboard.models import ( + Activity, Bounty, BountyDocuments, BountyFulfillment, BountyInvites, FeedbackEntry, HackathonEvent, Interest, + Profile, ProfileSerializer, UserAction, UserVerificationModel, +) +from dashboard.utils import profile_helper + +# from board.models import Notification + +# Create your views here. +@login_required +def board(request): + """Handle the board view.""" + + context = { + 'is_outside': True, + 'active': 'dashboard', + 'title': 'dashboard', + 'card_title': _('Dashboard'), + 'card_desc': _('Manage all your activity.'), + 'avatar_url': static('v2/images/helmet.png'), + } + return TemplateResponse(request, 'board.html', context) + +@login_required +def get_bounties(request): + + + results = [] + + if not settings.DEBUG: + network = 'mainnet' + else: + network = 'rinkeby' + + current_user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None + profile = ProfileSerializer(current_user.profile).data + bounties = Bounty.objects.filter( + bounty_owner_github_username__iexact=current_user.profile.handle, + network=network + ) + for bounty in bounties: + bounty_json = {} + bounty_json = bounty.to_standard_dict() + results.append(bounty_json) + # params['data'] = json.loads(json.dumps(results, default=str)) + return JsonResponse( + { + 'bounties': json.loads(json.dumps(results, default=str)), + 'profile': profile + }, + status=200) diff --git a/app/dashboard/models.py b/app/dashboard/models.py index c01406ca943..41b10249924 100644 --- a/app/dashboard/models.py +++ b/app/dashboard/models.py @@ -2541,6 +2541,7 @@ def get_eth_sum(self, sum_type='collected', network='mainnet', bounties=None): """ eth_sum = 0 + network = network or self.get_network() if not bounties: if sum_type == 'funded': @@ -2577,6 +2578,8 @@ def get_who_works_with(self, work_type='collected', network='mainnet', bounties= dict: list of the profiles that were worked with (key) and the number of times they occured """ + network = network or self.get_network() + if not bounties: if work_type == 'funded': bounties = self.bounties_funded.filter(network=network) @@ -2826,7 +2829,7 @@ def to_representation(self, instance): dict: The serialized Profile. """ - + return { 'id': instance.id, 'handle': instance.handle, @@ -2835,8 +2838,8 @@ def to_representation(self, instance): 'keywords': instance.keywords, 'url': instance.get_relative_url(), 'position': instance.get_contributor_leaderboard_index(), - 'organizations': instance.get_who_works_with(), - 'total_earned': instance.get_eth_sum() + 'organizations': instance.get_who_works_with(network=None), + 'total_earned': instance.get_eth_sum(network=None) } From 1ac38ef9994ef354565afd231b209bcfd94ed14b Mon Sep 17 00:00:00 2001 From: octavioamu Date: Wed, 5 Jun 2019 23:29:03 -0300 Subject: [PATCH 02/38] remove reverse test for dashboard --- app/app/tests/test_app_urls.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/app/tests/test_app_urls.py b/app/app/tests/test_app_urls.py index a10db8154b3..5340121c208 100644 --- a/app/app/tests/test_app_urls.py +++ b/app/app/tests/test_app_urls.py @@ -89,14 +89,14 @@ def test_faucet_resolve(self): self.assertEqual(resolve('/faucet').view_name, 'faucet') self.assertEqual(resolve('/faucet/').view_name, 'faucet') - def test_dashboard_reverse(self): - """Test the dashboard url and check the reverse.""" - self.assertEqual(reverse('dashboard'), '/dashboard') - - def test_dashboard_resolve(self): - """Test the dashboard url and check the resolution.""" - self.assertEqual(resolve('/dashboard').view_name, 'dashboard') - self.assertEqual(resolve('/dashboard/').view_name, 'dashboard') + # def test_dashboard_reverse(self): + # """Test the dashboard url and check the reverse.""" + # self.assertEqual(reverse('board_view'), '/dashboard') + + # def test_dashboard_resolve(self): + # """Test the dashboard url and check the resolution.""" + # self.assertEqual(resolve('/dashboard').view_name, 'board_view') + # self.assertEqual(resolve('/dashboard/').view_name, 'board_view') def test_explorer_reverse(self): """Test the explorer url and check the reverse.""" From 99fcc8e7beec97d90af0d0d6cb628dcd83fc3e25 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Thu, 6 Jun 2019 15:31:45 -0300 Subject: [PATCH 03/38] add fetch --- app/assets/v2/js/board.js | 27 +++++++++++++++++++++++++++ app/board/templates/board.html | 17 +++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 app/assets/v2/js/board.js diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js new file mode 100644 index 00000000000..e28742a9719 --- /dev/null +++ b/app/assets/v2/js/board.js @@ -0,0 +1,27 @@ +Vue.mixin({ + methods: { + fetchBounties: function(newPage) { + let vm = this; + let apiUrlbounties = `api/v0.1/get_bounties/`; + var getbounties = fetchData (apiUrlbounties, 'GET'); + + $.when(getbounties).then(function(response) { + vm.profile = response.profile; + }) + } + } +}); + +if (document.getElementById('gc-board')) { + var app = new Vue({ + delimiters: [ '[[', ']]' ], + el: '#gc-board', + data: { + profile: [] + }, + mounted() { + this.fetchBounties(); + } + + }); +} diff --git a/app/board/templates/board.html b/app/board/templates/board.html index 394042d649c..18ba7e9bc55 100644 --- a/app/board/templates/board.html +++ b/app/board/templates/board.html @@ -23,18 +23,21 @@ {% include 'shared/head.html' %} {% include 'shared/cards.html' %} - + {% include 'shared/top_nav.html' with class='d-md-flex' %} {% include 'shared/nav.html' %} -
- +
+
+ Welcome, [[ profile.handle ]]! -
-
-
+
+
+ +
+ {% include 'shared/footer.html' %} {% include 'shared/analytics.html' %} {% include 'shared/footer_scripts.html' with slim=1 %} @@ -43,5 +46,7 @@ + + From 63d6c776ecb864687b56bb776c1021a59d7d0df2 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Fri, 7 Jun 2019 10:46:09 -0300 Subject: [PATCH 04/38] add fields --- app/assets/v2/js/board.js | 6 +++- app/board/templates/board.html | 51 ++++++++++++++++++++++++++++++---- app/board/views.py | 19 +++++-------- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index e28742a9719..a47d5a13568 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -1,3 +1,5 @@ + + Vue.mixin({ methods: { fetchBounties: function(newPage) { @@ -7,6 +9,7 @@ Vue.mixin({ $.when(getbounties).then(function(response) { vm.profile = response.profile; + vm.bounties = response.bounties; }) } } @@ -17,7 +20,8 @@ if (document.getElementById('gc-board')) { delimiters: [ '[[', ']]' ], el: '#gc-board', data: { - profile: [] + profile: [], + bounties: [] }, mounted() { this.fetchBounties(); diff --git a/app/board/templates/board.html b/app/board/templates/board.html index 18ba7e9bc55..ff3a92ebe3d 100644 --- a/app/board/templates/board.html +++ b/app/board/templates/board.html @@ -26,16 +26,57 @@ {% include 'shared/top_nav.html' with class='d-md-flex' %} {% include 'shared/nav.html' %} -
- -
- Welcome, [[ profile.handle ]]! +
+
+
+
+
+
+
+ Welcome, [[ profile.handle ]]! +
+
+
-
+
+
+
+ + +
+
{% include 'shared/footer.html' %} diff --git a/app/board/views.py b/app/board/views.py index 053ff3d6d8d..c86c2d2e584 100644 --- a/app/board/views.py +++ b/app/board/views.py @@ -55,10 +55,6 @@ def board(request): @login_required def get_bounties(request): - - - results = [] - if not settings.DEBUG: network = 'mainnet' else: @@ -66,18 +62,17 @@ def get_bounties(request): current_user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None profile = ProfileSerializer(current_user.profile).data - bounties = Bounty.objects.filter( + bounties = Bounty.objects.current().filter( bounty_owner_github_username__iexact=current_user.profile.handle, network=network - ) - for bounty in bounties: - bounty_json = {} - bounty_json = bounty.to_standard_dict() - results.append(bounty_json) - # params['data'] = json.loads(json.dumps(results, default=str)) + ).values( + 'id','bounty_owner_github_username', 'github_comments', 'value_true', 'value_in_usdt_now', 'token_name', + 'github_url', 'idx_status', 'standard_bounties_id', 'title', 'bounty_type', 'bountyinvites', + 'interested', 'fulfillments' ) + return JsonResponse( { - 'bounties': json.loads(json.dumps(results, default=str)), + 'bounties': list(bounties), 'profile': profile }, status=200) From 28b404e6a5ade4c0fe33ee39b92fc07eb6315c13 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Fri, 7 Jun 2019 22:51:58 -0300 Subject: [PATCH 05/38] change query --- app/assets/v2/js/board.js | 3 ++- app/board/templates/board.html | 25 ++++++++++++++++++++++++- app/board/views.py | 26 ++++++++++++++++++++------ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index a47d5a13568..ca5492444ac 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -21,7 +21,8 @@ if (document.getElementById('gc-board')) { el: '#gc-board', data: { profile: [], - bounties: [] + bounties: [], + notifications: notifications }, mounted() { this.fetchBounties(); diff --git a/app/board/templates/board.html b/app/board/templates/board.html index ff3a92ebe3d..6e200611a01 100644 --- a/app/board/templates/board.html +++ b/app/board/templates/board.html @@ -42,6 +42,28 @@
+
+
+
+ {% trans 'Notifications' %} + {% trans 'See all' %} +
    +
  • + + + + + +

    +
    + +
  • +
+
+
+
diff --git a/app/board/views.py b/app/board/views.py index a7347da4a24..7857f13bc69 100644 --- a/app/board/views.py +++ b/app/board/views.py @@ -77,7 +77,16 @@ def get_bounties(request): bounty_json['avatar_url'] = bounty.avatar_url bounty_json['status'] = bounty.status bounty_json['is_project_type_fulfilled'] = bounty.is_project_type_fulfilled - print(bounty) + print(bounty.interested.select_related('profile').all()) + + # bounty_json['profile_pairs'] = bounty.profile_pairs + # bounty_json['interested'] = bounty.interested.select_related('profile').all() + if bounty.interested.exists(): + for profile in bounty.interested.select_related('profile').all().order_by('pk'): + interest= profile + bounty_json['interest']= interest.profile.handle + # bounty_json['is_fulfiller'] = bounty.is_fulfiller + print(bounty_json['interest']) # bounty_json['fulfillments'] = bounty.fulfillments all_bounties.append(bounty_json) From 209dacd70c8b170ab5ab3d4e73449c6e9a3f7f90 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Wed, 12 Jun 2019 10:34:52 -0300 Subject: [PATCH 07/38] change query --- app/board/views.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/board/views.py b/app/board/views.py index 7857f13bc69..2c53109e9f7 100644 --- a/app/board/views.py +++ b/app/board/views.py @@ -25,6 +25,7 @@ from django.contrib.staticfiles.templatetags.staticfiles import static from django.core.paginator import Paginator from django.core.serializers.json import DjangoJSONEncoder +from django.db.models import Count, Q from django.http import HttpResponse, JsonResponse from django.template.response import TemplateResponse from django.utils.translation import gettext_lazy as _ @@ -63,7 +64,9 @@ def get_bounties(request): current_user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None profile = ProfileSerializer(current_user.profile).data - bounties = Bounty.objects.current().prefetch_related('fulfillments', 'interested', 'interested__profile', 'feedbacks').filter( + bounties = Bounty.objects.current().prefetch_related( + 'fulfillments', 'interested', 'interested__profile', 'feedbacks').annotate( + count=Count('interested')).filter( bounty_owner_github_username__iexact=current_user.profile.handle, network=network ) @@ -77,16 +80,15 @@ def get_bounties(request): bounty_json['avatar_url'] = bounty.avatar_url bounty_json['status'] = bounty.status bounty_json['is_project_type_fulfilled'] = bounty.is_project_type_fulfilled - print(bounty.interested.select_related('profile').all()) + print(bounty.interested.select_related('profile').all().values()) # bounty_json['profile_pairs'] = bounty.profile_pairs - # bounty_json['interested'] = bounty.interested.select_related('profile').all() - if bounty.interested.exists(): - for profile in bounty.interested.select_related('profile').all().order_by('pk'): - interest= profile - bounty_json['interest']= interest.profile.handle + # bounty_json['interested'] = bounty.interested.select_related('profile').all().values() + # if bounty.interested.exists(): + # for profile in bounty.interested.select_related('profile').all().order_by('pk'): + # interest= profile + # bounty_json['interest']= interest.profile.handle # bounty_json['is_fulfiller'] = bounty.is_fulfiller - print(bounty_json['interest']) # bounty_json['fulfillments'] = bounty.fulfillments all_bounties.append(bounty_json) From b18a1991c318e2fd2109f6eba3d253ac0798e798 Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Thu, 4 Jul 2019 22:41:09 +0900 Subject: [PATCH 08/38] initial bounty lists and details --- app/dashboard/views.py | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index bd16034fdd5..80144cd88b6 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2812,3 +2812,59 @@ def get_hackathons(request): 'hackathons': events, } return TemplateResponse(request, 'dashboard/hackathons.html', params) + + +def dashboard_bounty_info(request, bounty_id): + """Per-bounty JSON data for the user dashboard""" + + user = request.user if request.user.is_authenticated else None + if not user: + return JsonResponse( + {'error': _('You must be authenticated via github to use this feature!')}, + status=401) + + bounty = Bounty.objects.get(id=bounty_id) + + return JsonResponse({'title': bounty.title, + 'token_name': bounty.token_name, + 'value_in_token': bounty.value_in_token, + 'value_in_used': bounty.get_value_in_usdt, + 'github_url': bounty.github_url, + 'absolute_url': bounty.absolute_url, + 'avatar_url': bounty.avatar_url, + 'project_type': bounty.project_type}) + + +def user_dashboard(request): + """JSON data for the user dashboard""" + + user = request.user if request.user.is_authenticated else None + if not user: + return JsonResponse( + {'error': _('You must be authenticated via github to use this feature!')}, + status=401) + + profile = request.user.profile + + interested_bounties = Bounty.objects.filter( + Q(idx_status='open') | Q(idx_status='open'), + interested__pending=True, + current_bounty=True, + bounty_owner_profile=profile + ).values_list('id', flat=True).order_by('-interested__created') + + submitted_bounties = Bounty.objects.filter( + Q(idx_status='submitted') | Q(override_status='submitted'), + current_bounty=True, + bounty_owner_profile=profile + ).values_list('id', flat=True).order_by('-fulfillments__created_on') + + expired_bounties = Bounty.objects.filter( + Q(idx_status='expired') | Q(override_status='expired'), + current_bounty=True, + bounty_owner_profile=profile + ).values_list('id', flat=True).order_by('-expires_date') + + return JsonResponse({'interested': interested_bounties, + 'submitted': submitted_bounties, + 'expired': expired_bounties}) From a0b711258e8a17737775d8be39286cf5d8cdc61e Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Thu, 4 Jul 2019 22:42:58 +0900 Subject: [PATCH 09/38] add expires_date --- app/dashboard/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 80144cd88b6..3f871887c28 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2832,7 +2832,8 @@ def dashboard_bounty_info(request, bounty_id): 'github_url': bounty.github_url, 'absolute_url': bounty.absolute_url, 'avatar_url': bounty.avatar_url, - 'project_type': bounty.project_type}) + 'project_type': bounty.project_type, + 'expires_date': bounty.expires_date}) def user_dashboard(request): From e65e56ce74cc7f001c050bb78fc032982c5a6e4b Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Fri, 5 Jul 2019 17:54:16 +0900 Subject: [PATCH 10/38] add interest profiles --- app/dashboard/views.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 3f871887c28..7f2a98b967f 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2825,6 +2825,25 @@ def dashboard_bounty_info(request, bounty_id): bounty = Bounty.objects.get(id=bounty_id) + if bounty.status == 'open': + interests = bounty.interested.prefetch_related('profile').filter(status='okay').all() + profiles = [ + {'interest': {'id': i.id, + 'issue_message': i.issue_message}, + 'handle': i.profile.handle, + 'avatar_url': i.profile.avatar_url, + 'star_rating': i.profile.get_average_star_rating['overall'], + 'total_rating': i.profile.get_average_star_rating['total_rating'], + 'fulfilled_bounties': len( + [b for b in i.profile.get_fulfilled_bounties]), + 'leaderboard_rank': i.profile.get_contributor_leaderbard_index(), + 'id': i.profile.id}] +} + elif bounty.status == 'submitted': + profiles = + elif bounty.status == 'expired': + profiles = [] + return JsonResponse({'title': bounty.title, 'token_name': bounty.token_name, 'value_in_token': bounty.value_in_token, @@ -2833,7 +2852,8 @@ def dashboard_bounty_info(request, bounty_id): 'absolute_url': bounty.absolute_url, 'avatar_url': bounty.avatar_url, 'project_type': bounty.project_type, - 'expires_date': bounty.expires_date}) + 'expires_date': bounty.expires_date, + 'profiles': profiles}) def user_dashboard(request): From 8d347f3ff1c2a8bc2de130ee00506e088df3ce2f Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Fri, 5 Jul 2019 18:04:33 +0900 Subject: [PATCH 11/38] add fulfillments --- app/dashboard/views.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 7f2a98b967f..799eaefd6b9 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2837,10 +2837,16 @@ def dashboard_bounty_info(request, bounty_id): 'fulfilled_bounties': len( [b for b in i.profile.get_fulfilled_bounties]), 'leaderboard_rank': i.profile.get_contributor_leaderbard_index(), - 'id': i.profile.id}] -} + 'id': i.profile.id} for i in interests] elif bounty.status == 'submitted': - profiles = + fulfillments = bounty.fulfillments.prefetch_related('profile').all() + profiles = [ + {'fulfillment': {'id': f.id, + 'metadata': f.metadata}, + 'handle': f.profile.handle, + 'avatar_url': f.profile.avatar_url, + 'preferred_payout_address': f.profile.preferred_payout_address, + 'id': f.profile.id} for f in fulfillments] elif bounty.status == 'expired': profiles = [] From 864d02255fed8dd9bef9bd3ab079ab373b598772 Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Fri, 5 Jul 2019 18:06:44 +0900 Subject: [PATCH 12/38] add else case --- app/dashboard/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 799eaefd6b9..b535eeab53b 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2847,7 +2847,7 @@ def dashboard_bounty_info(request, bounty_id): 'avatar_url': f.profile.avatar_url, 'preferred_payout_address': f.profile.preferred_payout_address, 'id': f.profile.id} for f in fulfillments] - elif bounty.status == 'expired': + else: profiles = [] return JsonResponse({'title': bounty.title, From 0bcdafe06dd68aa0e55dfc956691e5e383317925 Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Mon, 8 Jul 2019 22:17:59 +0900 Subject: [PATCH 13/38] fix bugs, add metadata --- app/app/urls.py | 4 ++++ app/dashboard/views.py | 41 +++++++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/app/urls.py b/app/app/urls.py index be74a42d439..46129c3aeaa 100644 --- a/app/app/urls.py +++ b/app/app/urls.py @@ -131,6 +131,10 @@ url(r'^dashboard/?', dashboard.views.dashboard, name='dashboard'), url(r'^explorer/?', dashboard.views.dashboard, name='explorer'), + # Funder dashboard + path('funder_dashboard/', dashboard.views.funder_dashboard, name='funder_dashboard'), + path('funder_dashboard/bounties//', dashboard.views.funder_dashboard_bounty_info, name='funder_dashboard_bounty_info'), + # Hackathon static page url(r'^hackathon/ethhack2019', dashboard.views.ethhack, name='ethhack_2019'), url(r'^hackathon/beyondblocks', dashboard.views.beyond_blocks_2019, name='beyond_blocks_2019'), diff --git a/app/dashboard/views.py b/app/dashboard/views.py index b535eeab53b..3cb6b4de568 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2814,7 +2814,7 @@ def get_hackathons(request): return TemplateResponse(request, 'dashboard/hackathons.html', params) -def dashboard_bounty_info(request, bounty_id): +def funder_dashboard_bounty_info(request, bounty_id): """Per-bounty JSON data for the user dashboard""" user = request.user if request.user.is_authenticated else None @@ -2840,29 +2840,34 @@ def dashboard_bounty_info(request, bounty_id): 'id': i.profile.id} for i in interests] elif bounty.status == 'submitted': fulfillments = bounty.fulfillments.prefetch_related('profile').all() - profiles = [ - {'fulfillment': {'id': f.id, - 'metadata': f.metadata}, - 'handle': f.profile.handle, - 'avatar_url': f.profile.avatar_url, - 'preferred_payout_address': f.profile.preferred_payout_address, - 'id': f.profile.id} for f in fulfillments] + profiles = [] + for f in fulfillments: + profile = {'fulfiller_metadata': f.fulfiller_metadata} + if f.profile: + profile.update( + {'handle': f.profile.handle, + 'avatar_url': f.profile.avatar_url, + 'preferred_payout_address': f.profile.preferred_payout_address, + 'id': f.profile.id}) + profiles.append(profile) else: profiles = [] return JsonResponse({'title': bounty.title, 'token_name': bounty.token_name, 'value_in_token': bounty.value_in_token, - 'value_in_used': bounty.get_value_in_usdt, + 'value_in_usd': bounty.get_value_in_usdt, 'github_url': bounty.github_url, 'absolute_url': bounty.absolute_url, 'avatar_url': bounty.avatar_url, 'project_type': bounty.project_type, 'expires_date': bounty.expires_date, + 'interested_comment': bounty.interested_comment, + 'submissions_comment': bounty.submissions_comment, 'profiles': profiles}) -def user_dashboard(request): +def funder_dashboard(request): """JSON data for the user dashboard""" user = request.user if request.user.is_authenticated else None @@ -2873,25 +2878,25 @@ def user_dashboard(request): profile = request.user.profile - interested_bounties = Bounty.objects.filter( + open_bounties = list(Bounty.objects.filter( Q(idx_status='open') | Q(idx_status='open'), - interested__pending=True, current_bounty=True, bounty_owner_profile=profile - ).values_list('id', flat=True).order_by('-interested__created') + ).values_list('id', flat=True).order_by('-interested__created')) - submitted_bounties = Bounty.objects.filter( + submitted_bounties = list(Bounty.objects.filter( Q(idx_status='submitted') | Q(override_status='submitted'), current_bounty=True, + fulfullments__accepted=False, bounty_owner_profile=profile - ).values_list('id', flat=True).order_by('-fulfillments__created_on') + ).values_list('id', flat=True).order_by('-fulfillments__created_on')) - expired_bounties = Bounty.objects.filter( + expired_bounties = list(Bounty.objects.filter( Q(idx_status='expired') | Q(override_status='expired'), current_bounty=True, bounty_owner_profile=profile - ).values_list('id', flat=True).order_by('-expires_date') + ).order_by('-expires_date').values_list('id', flat=True)) - return JsonResponse({'interested': interested_bounties, + return JsonResponse({'open': open_bounties, 'submitted': submitted_bounties, 'expired': expired_bounties}) From 5dcc27c485146cc58da4fa0bb475fbf3ae729aca Mon Sep 17 00:00:00 2001 From: Dan Lipert Date: Mon, 8 Jul 2019 22:33:31 +0900 Subject: [PATCH 14/38] fix typos --- app/dashboard/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 3cb6b4de568..25fc405f9dd 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2826,7 +2826,7 @@ def funder_dashboard_bounty_info(request, bounty_id): bounty = Bounty.objects.get(id=bounty_id) if bounty.status == 'open': - interests = bounty.interested.prefetch_related('profile').filter(status='okay').all() + interests = Interest.objects.prefetch_related('profile').filter(status='okay', bounty=bounty).all() profiles = [ {'interest': {'id': i.id, 'issue_message': i.issue_message}, @@ -2835,8 +2835,8 @@ def funder_dashboard_bounty_info(request, bounty_id): 'star_rating': i.profile.get_average_star_rating['overall'], 'total_rating': i.profile.get_average_star_rating['total_rating'], 'fulfilled_bounties': len( - [b for b in i.profile.get_fulfilled_bounties]), - 'leaderboard_rank': i.profile.get_contributor_leaderbard_index(), + [b for b in i.profile.get_fulfilled_bounties()]), + 'leaderboard_rank': i.profile.get_contributor_leaderboard_index(), 'id': i.profile.id} for i in interests] elif bounty.status == 'submitted': fulfillments = bounty.fulfillments.prefetch_related('profile').all() @@ -2887,7 +2887,7 @@ def funder_dashboard(request): submitted_bounties = list(Bounty.objects.filter( Q(idx_status='submitted') | Q(override_status='submitted'), current_bounty=True, - fulfullments__accepted=False, + fulfillments__accepted=False, bounty_owner_profile=profile ).values_list('id', flat=True).order_by('-fulfillments__created_on')) From 661a987a6f9853d753eec7b0e5dd8b378aa4aa79 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Tue, 16 Jul 2019 10:45:45 -0300 Subject: [PATCH 15/38] add style --- app/assets/v2/css/board.css | 21 +++++++ app/assets/v2/js/board.js | 11 +++- app/board/templates/board.html | 106 +++++++++++++++++++++------------ app/dashboard/views.py | 9 ++- 4 files changed, 106 insertions(+), 41 deletions(-) create mode 100644 app/assets/v2/css/board.css diff --git a/app/assets/v2/css/board.css b/app/assets/v2/css/board.css new file mode 100644 index 00000000000..52631676798 --- /dev/null +++ b/app/assets/v2/css/board.css @@ -0,0 +1,21 @@ +.line-deco:after { + content: ''; + position: absolute; + top: 34px; + border: 1px solid #F5F6F6; + bottom: 20px; + /* height: 100%; */ + left: 18px; +} + +.comment-plan { + color: #666666; + white-space: pre-line; + max-height: 100px; + overflow: hidden; + overflow-y: auto; + background: #F5F6F6; + padding: 1em; + margin-top: 1em; + border-radius: 5px; +} diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index ca5492444ac..b2ef23c7392 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -11,6 +11,15 @@ Vue.mixin({ vm.profile = response.profile; vm.bounties = response.bounties; }) + }, + isExpanded(key) { + return this.expandedGroup.indexOf(key) !== -1; + }, + toggleExpansion(key) { + if (this.isExpanded(key)) + this.expandedGroup.splice(this.expandedGroup.indexOf(key), 1); + else + this.expandedGroup.push(key); } } }); @@ -22,7 +31,7 @@ if (document.getElementById('gc-board')) { data: { profile: [], bounties: [], - notifications: notifications + expandedGroup: [] }, mounted() { this.fetchBounties(); diff --git a/app/board/templates/board.html b/app/board/templates/board.html index 2a3dab4e893..73bbdc2e47b 100644 --- a/app/board/templates/board.html +++ b/app/board/templates/board.html @@ -22,6 +22,8 @@ {% include 'shared/head.html' %} {% include 'shared/cards.html' %} + + {% include 'shared/top_nav.html' with class='d-md-flex' %} @@ -42,28 +44,7 @@
-
-
-
- {% trans 'Notifications' %} - {% trans 'See all' %} -
    -
  • - - - - - -

    -
    - -
  • -
-
-
-
+
    -
  • +
  • - +
    - +
    - ([[ contributor.avg_rating.total_rating ]] ratings) • - #[[ contributor.profile.position ]] contributor • - [[ contributor.profile.work_completed ]] bounties completed + ([[ contributor.total_rating ]] ratings) • + #[[ contributor.leaderboard_rank ]] contributor • + [[ contributor.fulfilled_bounties ]] bounties completed
    - - + +
    -
    Work Plan: 1. Look for inspiration from Dribbble - 2. Do a first draft on Photoshop by August 5th - 3. Make adjustments based on feedback -
    +
    [[ contributor.interest.issue_message]]
  • From a4324744d30e2265276deca4a398aeed76332809 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Sun, 21 Jul 2019 20:11:43 -0300 Subject: [PATCH 22/38] add be values --- app/dashboard/views.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 19bda110447..300dfa66899 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2868,25 +2868,29 @@ def funder_dashboard_bounty_info(request, bounty_id): else: profiles = [] - return JsonResponse({'title': bounty.title, - 'token_name': bounty.token_name, - 'value_in_token': bounty.value_in_token, - 'value_in_usd': bounty.get_value_in_usdt, - 'github_url': bounty.github_url, - 'absolute_url': bounty.absolute_url, - 'avatar_url': bounty.avatar_url, - 'project_type': bounty.project_type, - 'expires_date': bounty.expires_date, - 'interested_comment': bounty.interested_comment, - 'submissions_comment': bounty.submissions_comment, + return JsonResponse({ + # 'title': bounty.title, + # 'token_name': bounty.token_name, + # 'value_in_token': bounty.value_in_token, + # 'value_in_usd': bounty.get_value_in_usdt, + # 'github_url': bounty.github_url, + # 'absolute_url': bounty.absolute_url, + # 'avatar_url': bounty.avatar_url, + # 'project_type': bounty.project_type, + # 'expires_date': bounty.expires_date, + # 'interested_comment': bounty.interested_comment, + # 'submissions_comment': bounty.submissions_comment, + 'id': bounty.id, 'profiles': profiles}) def serialize_funder_dashboard_open_rows(bounties, interests): return [{'users_count': len([i for i in interests if b.pk in [i_b.pk for i_b in i.bounties]]), 'title': b.title, + 'id': b.id, 'token_name': b.token_name, 'value_in_token': b.value_in_token, + 'value_true': b.value_true, 'value_in_usd': b.get_value_in_usdt, 'github_url': b.github_url, 'absolute_url': b.absolute_url, @@ -2901,6 +2905,7 @@ def serialize_funder_dashboard_open_rows(bounties, interests): def serialize_funder_dashboard_submitted_rows(bounties): return [{'users_count': b.fulfillments.count(), 'title': b.title, + 'id': b.id, 'token_name': b.token_name, 'value_in_token': b.value_in_token, 'value_in_usd': b.get_value_in_usdt, From 22cac2ca91367a8525197837a1259871f50ffda5 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Sun, 21 Jul 2019 20:20:16 -0300 Subject: [PATCH 23/38] lint --- app/assets/v2/js/board.js | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index 07b052bdc7c..32c82e26188 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -1,7 +1,3 @@ -var interested =[{"profile":{"id":13,"handle":"octavioamu","github_url":"https://github.com/octavioamu","avatar_url":"/media/avatars/72f4f6d365732c50762730b1bc630379/octavioamu.png","keywords":["CSS","JavaScript","HTML","PHP"],"url":"/profile/octavioamu","position":0,"organizations":{},"total_earned":0, "work_completed":3}, -"avg_rating": {"overall": 2, "code_quality_rating": 0, "communication_rating": 0, "recommendation_rating": 0, "satisfaction_rating": 0, "speed_rating": 0, "total_rating": 0},"created":"2019-07-10T15:09:39.148065Z","pending":false,"signed_nda":null}, -{"profile":{"id":13,"handle":"oktopustester","github_url":"https://github.com/oktopustester","avatar_url":"/media/avatars/d7620227c9c48a33f697d7e875013d7e/oktopustester.png","keywords":["CSS","JavaScript","HTML","PHP"],"url":"/profile/oktopustester","position":0,"organizations":{},"total_earned":0, "work_completed":1}, -"avg_rating": {"overall": 3, "code_quality_rating": 0, "communication_rating": 0, "recommendation_rating": 0, "satisfaction_rating": 0, "speed_rating": 0, "total_rating": 0}, "created":"2019-07-10T15:09:39.148065Z","pending":false,"signed_nda":null}] Vue.mixin({ methods: { @@ -11,12 +7,13 @@ Vue.mixin({ let getbounties = fetchData (apiUrlbounties, 'GET'); $.when(getbounties).then(function(response) { - vm.$set(vm.bounties,type, response) - }) + vm.$set(vm.bounties, type, response); + }); }, fetchApplicants: function(id, key, type) { let vm = this; let apiUrlApplicants = `/funder_dashboard/bounties/${id}/`; + if (vm.bounties[type][key].contributors) { return; } @@ -24,26 +21,27 @@ Vue.mixin({ $.when(getApplicants).then(function(response) { - vm.$set(vm.bounties[type][key],'contributors', response.profiles) + vm.$set(vm.bounties[type][key], 'contributors', response.profiles); // vm.$set(vm.openBounties[key],'contributors', response.profiles) - }) + }); }, isExpanded(key) { - return this.expandedGroup.indexOf(key) !== -1; + return this.expandedGroup.indexOf(key) !== -1; }, toggleCollapse(key) { - if (this.isExpanded(key)) + if (this.isExpanded(key)) { this.expandedGroup.splice(this.expandedGroup.indexOf(key), 1); - else + } else { this.expandedGroup.push(key); + } }, startWork(key, bountyPk, profileId) { let vm = this; - vm.disabledBtn = key let url = `/actions/bounty/${bountyPk}/interest/${profileId}/interested/`; let postStartpWork = fetchData (url, 'POST'); - console.log(key) + + vm.disabledBtn = key; $.when(postStartpWork).then(response => { vm.contributors.splice(key, 1); @@ -52,16 +50,17 @@ Vue.mixin({ }, error => { vm.disabledBtn = ''; let msg = error.responseJSON.error || 'got an error. please try again, or contact support@gitcoin.co'; - console.log(error.responseJSON.error) + + console.log(error.responseJSON.error); _alert({ message: gettext(msg) }, 'error'); - }) + }); }, stopWork(key, bountyPk, profileId) { let vm = this; - vm.disabledBtn = key let url = `/actions/bounty/${bountyPk}/interest/${profileId}/uninterested/`; let postStartpWork = fetchData (url, 'POST'); - console.log(key) + + vm.disabledBtn = key; $.when(postStartpWork).then(response => { vm.contributors.splice(key, 1); @@ -70,9 +69,10 @@ Vue.mixin({ }, error => { vm.disabledBtn = ''; let msg = error.responseJSON.error || 'got an error. please try again, or contact support@gitcoin.co'; - console.log(error.responseJSON.error) + + console.log(error.responseJSON.error); _alert({ message: gettext(msg) }, 'error'); - }) + }); } } }); @@ -100,9 +100,9 @@ if (document.getElementById('gc-board')) { } Vue.filter('pluralize', (word, amount, singular, plural) => { - plural = plural || 's' - singular = singular || '' - return amount > 1 ? `${word + plural}` : `${word + singular}` + plural = plural || 's'; + singular = singular || ''; + return amount > 1 ? `${word + plural}` : `${word + singular}`; }); Vue.filter('moment', (date) => { From b28661777ec44bb2e95a6d2365ea1aec0fe71361 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Sun, 21 Jul 2019 20:35:38 -0300 Subject: [PATCH 24/38] remove separated app --- app/app/settings.py | 3 +- app/app/urls.py | 2 +- app/board/__init__.py | 0 app/board/admin.py | 3 - app/board/apps.py | 5 - app/board/migrations/__init__.py | 0 app/board/models.py | 3 - app/board/tests.py | 3 - app/board/urls.py | 29 ----- app/board/views.py | 103 ------------------ app/{board => dashboard}/templates/board.html | 0 app/dashboard/views.py | 15 +++ 12 files changed, 17 insertions(+), 149 deletions(-) delete mode 100644 app/board/__init__.py delete mode 100644 app/board/admin.py delete mode 100644 app/board/apps.py delete mode 100644 app/board/migrations/__init__.py delete mode 100644 app/board/models.py delete mode 100644 app/board/tests.py delete mode 100644 app/board/urls.py delete mode 100644 app/board/views.py rename app/{board => dashboard}/templates/board.html (100%) diff --git a/app/app/settings.py b/app/app/settings.py index 945a42e7d0c..14b12c30812 100644 --- a/app/app/settings.py +++ b/app/app/settings.py @@ -113,7 +113,6 @@ 'revenue', 'event_ethdenver2019', 'inbox', - 'board', ] MIDDLEWARE = [ @@ -143,7 +142,7 @@ TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': ['retail/templates/', 'dataviz/templates', 'kudos/templates', 'inbox/templates', 'board/templates'], + 'DIRS': ['retail/templates/', 'dataviz/templates', 'kudos/templates', 'inbox/templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/app/app/urls.py b/app/app/urls.py index ca5a339eeb7..057e190e337 100644 --- a/app/app/urls.py +++ b/app/app/urls.py @@ -65,7 +65,7 @@ path('inbox/', include('inbox.urls', namespace='inbox')), # board - path('dashboard/', include('board.urls', namespace='board')), + path('dashboard/', dashboard.views.board, name='dashboard'), # kudos path('kudos/', kudos.views.about, name='kudos_main'), diff --git a/app/board/__init__.py b/app/board/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/board/admin.py b/app/board/admin.py deleted file mode 100644 index 8c38f3f3dad..00000000000 --- a/app/board/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/app/board/apps.py b/app/board/apps.py deleted file mode 100644 index a943e308fb9..00000000000 --- a/app/board/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class BoardConfig(AppConfig): - name = 'board' diff --git a/app/board/migrations/__init__.py b/app/board/migrations/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/board/models.py b/app/board/models.py deleted file mode 100644 index 71a83623907..00000000000 --- a/app/board/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/app/board/tests.py b/app/board/tests.py deleted file mode 100644 index 7ce503c2dd9..00000000000 --- a/app/board/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/app/board/urls.py b/app/board/urls.py deleted file mode 100644 index 97d199f5e5d..00000000000 --- a/app/board/urls.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -"""Define url for the inbox app. - -Copyright (C) 2019 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 . - -""" - -from django.urls import path - -from board import views - -app_name = 'board' -urlpatterns = [ - path('', views.board, name='board_view'), - path('api/v0.1/get_bounties/', views.get_bounties, name='get_bounties'), -] diff --git a/app/board/views.py b/app/board/views.py deleted file mode 100644 index 2c53109e9f7..00000000000 --- a/app/board/views.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- -"""Define view for the inbox app. - -Copyright (C) 2019 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 . - -""" - -import json - -from django.conf import settings -from django.contrib.auth.decorators import login_required -from django.contrib.staticfiles.templatetags.staticfiles import static -from django.core.paginator import Paginator -from django.core.serializers.json import DjangoJSONEncoder -from django.db.models import Count, Q -from django.http import HttpResponse, JsonResponse -from django.template.response import TemplateResponse -from django.utils.translation import gettext_lazy as _ -from django.views.decorators.csrf import csrf_exempt -from django.views.decorators.http import require_GET, require_http_methods - -from dashboard.models import ( - Activity, Bounty, BountyDocuments, BountyFulfillment, BountyInvites, FeedbackEntry, HackathonEvent, Interest, - Profile, ProfileSerializer, UserAction, UserVerificationModel, -) -from dashboard.utils import profile_helper - -# from board.models import Notification - -# Create your views here. -@login_required -def board(request): - """Handle the board view.""" - - context = { - 'is_outside': True, - 'active': 'dashboard', - 'title': 'dashboard', - 'card_title': _('Dashboard'), - 'card_desc': _('Manage all your activity.'), - 'avatar_url': static('v2/images/helmet.png'), - } - return TemplateResponse(request, 'board.html', context) - -@login_required -def get_bounties(request): - if not settings.DEBUG: - network = 'mainnet' - else: - network = 'rinkeby' - - current_user = request.user if hasattr(request, 'user') and request.user.is_authenticated else None - profile = ProfileSerializer(current_user.profile).data - bounties = Bounty.objects.current().prefetch_related( - 'fulfillments', 'interested', 'interested__profile', 'feedbacks').annotate( - count=Count('interested')).filter( - bounty_owner_github_username__iexact=current_user.profile.handle, - network=network - ) - all_bounties = [] - for bounty in bounties: - bounty_json = { - k: getattr(bounty, k) for k in - ['id','bounty_owner_github_username', 'github_comments','value_true', 'value_in_usdt_now', 'token_name', - 'github_url', 'idx_status', 'standard_bounties_id', 'title', 'bounty_type', 'funding_organisation', 'metadata']} - bounty_json['url'] = bounty.url - bounty_json['avatar_url'] = bounty.avatar_url - bounty_json['status'] = bounty.status - bounty_json['is_project_type_fulfilled'] = bounty.is_project_type_fulfilled - print(bounty.interested.select_related('profile').all().values()) - - # bounty_json['profile_pairs'] = bounty.profile_pairs - # bounty_json['interested'] = bounty.interested.select_related('profile').all().values() - # if bounty.interested.exists(): - # for profile in bounty.interested.select_related('profile').all().order_by('pk'): - # interest= profile - # bounty_json['interest']= interest.profile.handle - # bounty_json['is_fulfiller'] = bounty.is_fulfiller - # bounty_json['fulfillments'] = bounty.fulfillments - all_bounties.append(bounty_json) - - return JsonResponse( - { - 'bounties': json.loads(json.dumps(all_bounties, cls=DjangoJSONEncoder)), - 'profile': profile - }, - status=200) -# 'value_true', 'value_in_usdt_now', 'token_name', -# 'github_url', 'idx_status', 'standard_bounties_id', 'title', 'bounty_type', 'bountyinvites', -# 'interested', 'fulfillments', 'current_bounty', 'funding_organisation', 'metadata', 'activities' diff --git a/app/board/templates/board.html b/app/dashboard/templates/board.html similarity index 100% rename from app/board/templates/board.html rename to app/dashboard/templates/board.html diff --git a/app/dashboard/views.py b/app/dashboard/views.py index 300dfa66899..6eb66e099d3 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -2829,6 +2829,21 @@ def get_hackathons(request): return TemplateResponse(request, 'dashboard/hackathons.html', params) +@login_required +def board(request): + """Handle the board view.""" + + context = { + 'is_outside': True, + 'active': 'dashboard', + 'title': 'dashboard', + 'card_title': _('Dashboard'), + 'card_desc': _('Manage all your activity.'), + 'avatar_url': static('v2/images/helmet.png'), + } + return TemplateResponse(request, 'board.html', context) + + def funder_dashboard_bounty_info(request, bounty_id): """Per-bounty JSON data for the user dashboard""" From 5b273eac22b5b933846f629dee708d3a4765de63 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Tue, 23 Jul 2019 18:22:47 -0300 Subject: [PATCH 25/38] add empty state --- app/assets/v2/css/board.css | 4 + app/assets/v2/images/zero-bounties.svg | 1 + app/assets/v2/js/board.js | 13 ++- app/dashboard/templates/board.html | 133 ++++++++++++++++++------- app/dashboard/views.py | 5 +- 5 files changed, 117 insertions(+), 39 deletions(-) create mode 100644 app/assets/v2/images/zero-bounties.svg diff --git a/app/assets/v2/css/board.css b/app/assets/v2/css/board.css index 02519aa09e7..5b57fceaf8a 100644 --- a/app/assets/v2/css/board.css +++ b/app/assets/v2/css/board.css @@ -35,3 +35,7 @@ display: block; font-size: 2rem; } + +.light-blue { + color: #008EFF; +} diff --git a/app/assets/v2/images/zero-bounties.svg b/app/assets/v2/images/zero-bounties.svg new file mode 100644 index 00000000000..a0d06e64ce7 --- /dev/null +++ b/app/assets/v2/images/zero-bounties.svg @@ -0,0 +1 @@ + diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index 32c82e26188..5d865b2c403 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -36,6 +36,12 @@ Vue.mixin({ this.expandedGroup.push(key); } }, + mutateWorkerAction(bountyUrl, action, worker) { + let vm = this; + let url = `${bountyUrl}/?mutate_worker_action=${action}&worker=${octavioamu}`; + let postWorkerAction = fetchData (url, 'POST'); + + }, startWork(key, bountyPk, profileId) { let vm = this; let url = `/actions/bounty/${bountyPk}/interest/${profileId}/interested/`; @@ -102,7 +108,12 @@ if (document.getElementById('gc-board')) { Vue.filter('pluralize', (word, amount, singular, plural) => { plural = plural || 's'; singular = singular || ''; - return amount > 1 ? `${word + plural}` : `${word + singular}`; + return amount !== 1 ? `${word + plural}` : `${word + singular}`; +}); + +Vue.filter('truncate', (account, num) => { + num = !num ? num = 4 : num; + return account.substr(0, num + 2) + '\u2026' + account.substr(-num); }); Vue.filter('moment', (date) => { diff --git a/app/dashboard/templates/board.html b/app/dashboard/templates/board.html index 8a8ecdc3b9d..4b84ee9e3df 100644 --- a/app/dashboard/templates/board.html +++ b/app/dashboard/templates/board.html @@ -35,7 +35,7 @@
-
+
@@ -58,12 +58,12 @@
-
+
[[ bounties.open.length ]] Open [[ 'Bount' | pluralize(bounties.open.length, 'y', 'ies') ]]
[[ contributor.interest.issue_message]]
@@ -128,6 +134,15 @@
+
  • + +

    + You haven’t funded any issues yet. +

    +

    Fund an Issue or check out our Funders Guide to start getting contributors for your project!

    +

    Have any question? Chat with us on Slack!

    + Fund an Issue +
  • @@ -137,37 +152,38 @@
    -
    -
    [[bounties.submitted ? bounties.submitted.length : 0 ]] Submitted Bounties
    +
    + +
    [[ bounties.submitted.length ]] Submitted [[ 'Bount' | pluralize(bounties.submitted.length, 'y', 'ies') ]]
    @@ -163,7 +165,7 @@

    [[ bounties.submitted.length ]] Submitted [[ 'Bount' | pluralize(bounties.submitted.length, 'y', 'ies') ]]
      -
    • +
    • @@ -180,7 +182,7 @@

      [[ bounty.project_type ]] [[ bounty.value_true ]] [[ bounty.token_name ]] ([[ bounty.value_in_usd ]] USD) View Issue Details @@ -200,7 +202,7 @@

      [[ contributor.fulfiller_metadata.fulfiller | truncate ]] Submitted [[ contributor.created_on | moment]] @@ -231,7 +233,7 @@

      [[ bounties.expired.length ]] Expired [[ 'Bount' | pluralize(bounties.expired.length, 'y', 'ies') ]]
        -
      • +
      • @@ -248,7 +250,7 @@

        [[ bounty.project_type ]] [[ bounty.value_true ]] [[ bounty.token_name ]] ([[ bounty.value_in_usd ]] USD) View Issue Details @@ -299,7 +301,7 @@

        [[ contributorBounties.work_in_progress.length ]] [[ 'Bount' | pluralize(contributorBounties.work_in_progress.length, 'y', 'ies') ]] in Progress

    • @@ -346,10 +352,10 @@

      -
      [[ contributorBounties.interested.length ]] [[ 'Bount' | pluralize(contributorBounties.work_in_progress.length, 'y', 'ies') ]] Applied

      +
      [[ contributorBounties.interested.length ]] [[ 'Bount' | pluralize(contributorBounties.interested.length, 'y', 'ies') ]] Applied


    • @@ -393,7 +402,7 @@

      [[ contributorBounties.submitted.length ]] Work Submitted
        -
      • +
      • @@ -410,7 +419,7 @@

        [[ bounty.project_type ]] [[ bounty.value_true ]] [[ bounty.token_name ]] ([[ bounty.value_in_usd ]] USD) View Issue Details @@ -437,6 +446,11 @@

        {% include 'shared/analytics.html' %} {% include 'shared/footer_scripts.html' with slim=1 %} + From 16aebf786c48bf15af56db396cb473c6a9b50884 Mon Sep 17 00:00:00 2001 From: octavioamu Date: Mon, 29 Jul 2019 14:15:07 -0300 Subject: [PATCH 31/38] add loading --- app/assets/v2/css/vue-loader.css | 130 +++++++++++++++++++++++++++++ app/assets/v2/js/board.js | 14 +++- app/dashboard/templates/board.html | 13 ++- 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 app/assets/v2/css/vue-loader.css diff --git a/app/assets/v2/css/vue-loader.css b/app/assets/v2/css/vue-loader.css new file mode 100644 index 00000000000..830558cae03 --- /dev/null +++ b/app/assets/v2/css/vue-loader.css @@ -0,0 +1,130 @@ +/* loading */ +.rhombus-spinner { + height: 65px; + width: 65px; + position: relative; + transform: rotate(45deg); + margin: auto; + color: #25E899; +} + +.rhombus-spinner .rhombus { + height: calc(65px / 7.5); + width: calc(65px / 7.5); + animation-duration: 2000ms; + top: calc(65px / 2.3077); + left: calc(65px / 2.3077); + border-radius: 30px; + background-color: currentColor; + position: absolute; + animation-iteration-count: infinite; +} + +.rhombus-spinner .rhombus:nth-child(2n+0) { + margin-right: 0; +} + +.rhombus-spinner .rhombus.child-1 { + animation-name: rhombus-spinner-animation-child-1; + animation-delay: calc(100ms * 1); +} + +.rhombus-spinner .rhombus.child-2 { + animation-name: rhombus-spinner-animation-child-2; + animation-delay: calc(100ms * 2); +} + +.rhombus-spinner .rhombus.child-3 { + animation-name: rhombus-spinner-animation-child-3; + animation-delay: calc(100ms * 3); +} + +.rhombus-spinner .rhombus.child-4 { + animation-name: rhombus-spinner-animation-child-4; + animation-delay: calc(100ms * 4); +} + +.rhombus-spinner .rhombus.child-5 { + animation-name: rhombus-spinner-animation-child-5; + animation-delay: calc(100ms * 5); +} + +.rhombus-spinner .rhombus.child-6 { + animation-name: rhombus-spinner-animation-child-6; + animation-delay: calc(100ms * 6); +} + +.rhombus-spinner .rhombus.child-7 { + animation-name: rhombus-spinner-animation-child-7; + animation-delay: calc(100ms * 7); +} + +.rhombus-spinner .rhombus.child-8 { + animation-name: rhombus-spinner-animation-child-8; + animation-delay: calc(100ms * 8); +} + +.rhombus-spinner .rhombus.big { + height: calc(65px / 3); + width: calc(65px / 3); + top: calc(65px / 3); + left: calc(65px / 3); + background-color: #3E00FF; + animation: rhombus-spinner-animation-child-big 2s infinite; + animation-duration: 2000ms; + animation-delay: 0.5s; +} + +@keyframes rhombus-spinner-animation-child-1 { + 50% { + transform: translate(-325%, -325%); + } +} + +@keyframes rhombus-spinner-animation-child-2 { + 50% { + transform: translate(0, -325%); + } +} + +@keyframes rhombus-spinner-animation-child-3 { + 50% { + transform: translate(325%, -325%); + } +} + +@keyframes rhombus-spinner-animation-child-4 { + 50% { + transform: translate(325%, 0); + } +} + +@keyframes rhombus-spinner-animation-child-5 { + 50% { + transform: translate(325%, 325%); + } +} + +@keyframes rhombus-spinner-animation-child-6 { + 50% { + transform: translate(0, 325%); + } +} + +@keyframes rhombus-spinner-animation-child-7 { + 50% { + transform: translate(-325%, 325%); + } +} + +@keyframes rhombus-spinner-animation-child-8 { + 50% { + transform: translate(-325%, 0); + } +} + +@keyframes rhombus-spinner-animation-child-big { + 50% { + transform: scale(0.5); + } +} diff --git a/app/assets/v2/js/board.js b/app/assets/v2/js/board.js index 9560731b2f8..28883881001 100644 --- a/app/assets/v2/js/board.js +++ b/app/assets/v2/js/board.js @@ -11,6 +11,7 @@ Vue.mixin({ $.when(getbounties).then(function(response) { vm.$set(vm.bounties, type, response); + vm.isLoading[type] = false; }); }, fetchApplicants: function(id, key, type) { @@ -24,6 +25,7 @@ Vue.mixin({ $.when(getApplicants).then(function(response) { vm.$set(vm.bounties[type][key], 'contributors', response.profiles); + vm.isLoading[`${type}Contrib`] = false; }); }, fetchContributorBounties: function(type) { @@ -33,6 +35,8 @@ Vue.mixin({ $.when(getbounties).then(function(response) { vm.$set(vm.contributorBounties, type, response); + vm.isLoading[type] = false; + }); }, isExpanded(key, type) { @@ -129,7 +133,15 @@ if (document.getElementById('gc-board')) { contributorBounties: contributorBounties, expandedGroup: {'submitted': [], 'open': []}, disabledBtn: false, - authProfile: authProfile + authProfile: authProfile, + isLoading: { + 'open':true, + 'openContrib':true, + 'submitted':true, + 'submittedContrib':true, + 'interest':true, + 'contributorBounties':true, + } }, mounted() { this.tabOnLoad(); diff --git a/app/dashboard/templates/board.html b/app/dashboard/templates/board.html index 6794bfb57c5..caeec3c4e10 100644 --- a/app/dashboard/templates/board.html +++ b/app/dashboard/templates/board.html @@ -22,6 +22,8 @@ {% include 'shared/head.html' %} {% include 'shared/cards.html' %} + + @@ -140,9 +142,11 @@ EXPLORE USER DIRECTORY

      + +

    -
  • +
  • [[isLoading.open]]

    You haven’t funded any issues yet. @@ -152,6 +156,8 @@

    Fund an Issue

  • + +
    @@ -215,12 +221,16 @@

    +

  • You have no bounties with submittions.

  • + + +
    @@ -445,6 +455,7 @@

    {% include 'shared/footer.html' %} {% include 'shared/analytics.html' %} {% include 'shared/footer_scripts.html' with slim=1 %} +