-
-
Notifications
You must be signed in to change notification settings - Fork 774
[WIP][WOC] feedback implementation (continuation of #1464) #3424
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
Changes from all commits
f662ff1
1635061
e7d9b13
19729c9
ca6644c
3323668
fdcf1de
4ccbda7
bc7e5b1
f39645e
9ed8d67
38f1364
dfa7783
370237c
19d6184
822c107
7ceb038
fe013c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1006,6 +1006,49 @@ input.is-invalid { | |
width: auto; | ||
} | ||
|
||
.rating { | ||
width:160px; | ||
} | ||
.rating span { float:right; position:relative; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Empty line between css rules :P |
||
.rating span input { | ||
position:absolute; | ||
top:0px; | ||
left:0px; | ||
opacity:0; | ||
} | ||
.rating span label { | ||
display:inline-block; | ||
width:30px; | ||
height:30px; | ||
text-align:center; | ||
color:#FFF; | ||
font-size:25px; | ||
margin-right:2px; | ||
line-height:30px; | ||
border-radius:50%; | ||
-webkit-border-radius:50%; | ||
} | ||
.rating span label i { | ||
color:#ccc; | ||
} | ||
|
||
.rating span:hover ~ span label i, | ||
.rating span:hover label i { | ||
opacity: 0.5; | ||
} | ||
.rating span.checked label i, | ||
.rating span.checked ~ span label i | ||
{ | ||
opacity: 1; | ||
} | ||
|
||
.rating span:hover ~ span label i, | ||
.rating span:hover label i, | ||
.rating span.checked label i, | ||
.rating span.checked ~ span label i { | ||
color: rgb(18,199,113); | ||
} | ||
|
||
.bounty_box { | ||
border: 5px solid white; | ||
width: 100%; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,19 @@ | ||
/* eslint-disable no-console */ | ||
window.onload = function() { | ||
|
||
// Check Radio-box | ||
$('.rating input:radio').attr('checked', false); | ||
|
||
$('.rating input').click(function() { | ||
$('.rating span').removeClass('checked'); | ||
$(this).parent().addClass('checked'); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Arrow functions :P |
||
|
||
$('input:radio').change( | ||
function() { | ||
var userRating = this.value; | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this variable used anywhere? |
||
|
||
// a little time for web3 injection | ||
setTimeout(function() { | ||
waitforWeb3(actions_page_warn_if_not_on_same_network); | ||
|
@@ -73,7 +87,12 @@ window.onload = function() { | |
platform: 'gitcoin', | ||
schemaVersion: '0.1', | ||
schemaName: 'gitcoinFulfillment' | ||
} | ||
}, | ||
review: { | ||
rating: data.rating?data.rating:-1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Infix operators must be spaced. (space-infix-ops) |
||
comment: data.review?data.review:"No comment given.", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Infix operators must be spaced. (space-infix-ops) |
||
reviewType: "worker" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strings must use singlequote. (quotes) |
||
} | ||
}; | ||
|
||
var _callback = function(error, result) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
from .models import ( | ||
Activity, BlockedUser, Bounty, BountyFulfillment, BountySyncRequest, CoinRedemption, CoinRedemptionRequest, | ||
Interest, LabsResearch, Profile, SearchHistory, Subscription, Tip, TokenApproval, Tool, ToolVote, UserAction, | ||
FeedbackEntry, | ||
) | ||
|
||
|
||
|
@@ -68,6 +69,9 @@ class UserActionAdmin(admin.ModelAdmin): | |
search_fields = ['action', 'ip_address', 'metadata', 'profile__handle'] | ||
ordering = ['-id'] | ||
|
||
class FeedbackAdmin(admin.ModelAdmin): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E302 expected 2 blank lines, found 1 |
||
search_fields = ['sender_profile','receiver_profile','bounty','feedbackType'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E231 missing whitespace after ',' |
||
ordering = ['-id'] | ||
|
||
class ProfileAdmin(admin.ModelAdmin): | ||
raw_id_fields = ['user', 'preferred_kudos_wallet'] | ||
|
@@ -168,4 +172,5 @@ def network_link(self, instance): | |
admin.site.register(CoinRedemptionRequest, GeneralAdmin) | ||
admin.site.register(Tool, GeneralAdmin) | ||
admin.site.register(ToolVote, ToolVoteAdmin) | ||
admin.site.register(FeedbackEntry, FeedbackAdmin) | ||
admin.site.register(LabsResearch) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,7 +44,7 @@ | |
from ratelimit.decorators import ratelimit | ||
from redis_semaphore import NotAvailable as SemaphoreExists | ||
|
||
from .models import Profile | ||
from .models import Profile, FeedbackEntry | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -333,7 +333,9 @@ def handle_bounty_fulfillments(fulfillments, new_bounty, old_bounty): | |
except Exception as e: | ||
logger.error(f'{e} during new fulfillment creation for {new_bounty}') | ||
continue | ||
return new_bounty.fulfillments.all() | ||
|
||
if new_bounty: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the goal of this check on |
||
return new_bounty.fulfillments.all() | ||
|
||
|
||
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id): | ||
|
@@ -522,12 +524,13 @@ def process_bounty_details(bounty_details): | |
bounty_data = bounty_details.get('data') or {} | ||
bounty_payload = bounty_data.get('payload', {}) | ||
meta = bounty_data.get('meta', {}) | ||
bounty_review = bounty_data.get('review', {}) | ||
|
||
# what schema are we working with? | ||
schema_name = meta.get('schemaName') | ||
schema_name = meta.get('schemaName', 'Unknown') | ||
schema_version = meta.get('schemaVersion', 'Unknown') | ||
if not schema_name or schema_name != 'gitcoinBounty': | ||
logger.info('Unknown Schema: Unknown - Version: %s', schema_version) | ||
logger.info('Unknown Schema: %s - Version: %s', schema_name, schema_version) | ||
return (False, None, None) | ||
|
||
# Create new bounty (but only if things have changed) | ||
|
@@ -545,11 +548,33 @@ def process_bounty_details(bounty_details): | |
new_bounty = create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id) | ||
|
||
if new_bounty: | ||
create_new_feedback(new_bounty, bounty_review) | ||
return (did_change, latest_old_bounty, new_bounty) | ||
return (did_change, latest_old_bounty, latest_old_bounty) | ||
except SemaphoreExists: | ||
return (did_change, latest_old_bounty, latest_old_bounty) | ||
|
||
def create_new_feedback(new_bounty, feedback_dict): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E302 expected 2 blank lines, found 1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ever considered putting this logic into model ? models looks anemic and you create 'create' method in helpers while it can belong to Feedback itself
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, considered that already. The main thing was to get it working, since we are having a IPFS bridge here and it wasn't working very well. especially because we do not simply provide the IPFS later on to the create functions, but actually parse them and return a DIFFERENT json structure than the one we pass into IPFS. Hence those methods are still from the "trying to get this to work" era. |
||
feedbackType = feedback_dict.get('feedbackType','???') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E231 missing whitespace after ',' |
||
if feedbackType == 'worker': | ||
sender = new_bounty.bounty_owner_profile | ||
receiver = new_bounty.activities.last().profile | ||
else: | ||
receiver = new_bounty.bounty_owner_profile | ||
sender = new_bounty.activities.last().profile | ||
|
||
kwargs = { | ||
'bounty': new_bounty, | ||
'sender_profile': sender, | ||
'receiver_profile': receiver, | ||
'rating': feedback_dict.get('rating', '-1'), | ||
'comment': feedback_dict.get('comment', 'No comment in IPFS entry.'), | ||
'feedbackType': feedbackType | ||
} | ||
|
||
e = FeedbackEntry.objects.create(**kwargs) | ||
e.save() | ||
pass | ||
|
||
def get_bounty_data_for_activity(bounty): | ||
"""Get data from bounty to be saved in activity records. | ||
|
@@ -625,18 +650,25 @@ def record_bounty_activity(event_name, old_bounty, new_bounty, _fulfillment=None | |
'increased_bounty', | ||
'worker_rejected', | ||
'bounty_changed'] | ||
logger.info(f"record_bounty_activity > profile at start: {user_profile}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets remove these extra logging statements before we merge this PR 👍 |
||
if event_name not in funder_actions: | ||
if not fulfillment: | ||
logger.info(f"record_bounty_activity > not fulfillment, event_name: {event_name}") | ||
fulfillment = new_bounty.fulfillments.order_by('-pk').first() | ||
if event_name == 'work_done': | ||
fulfillment = new_bounty.fulfillments.filter(accepted=True).latest('fulfillment_id') | ||
if fulfillment: | ||
logger.info(f"record_bounty_activity > fulfillment! {fulfillment}") | ||
user_profile = Profile.objects.filter(handle__iexact=fulfillment.fulfiller_github_username).first() | ||
if not user_profile: | ||
logger.info(f"record_bounty_activity > not user_profile :-(") | ||
user_profile = sync_profile(fulfillment.fulfiller_github_username) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. W293 blank line contains whitespace |
||
except Exception as e: | ||
logger.error(f'{e} during record_bounty_activity for {new_bounty}') | ||
|
||
logger.info(f"record_bounty_activity > user_profile: {user_profile}") | ||
|
||
if user_profile: | ||
return Activity.objects.create( | ||
profile=user_profile, | ||
|
@@ -729,6 +761,8 @@ def process_bounty_changes(old_bounty, new_bounty): | |
# record a useraction for this | ||
record_user_action(event_name, old_bounty, new_bounty) | ||
record_bounty_activity(event_name, old_bounty, new_bounty) | ||
# check for review{} in here, create review object, wheeee. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this comment referring to? |
||
|
||
|
||
# Build profile pairs list | ||
if new_bounty.fulfillments.exists(): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Generated by Django 2.1.4 on 2019-01-11 00:48 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
import economy.models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('dashboard', '0006_bounty_estimated_hours'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='BountyComment', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_on', models.DateTimeField(db_index=True, default=economy.models.get_time)), | ||
('modified_on', models.DateTimeField(default=economy.models.get_time)), | ||
('comment', models.TextField(blank=True)), | ||
('rating', models.IntegerField(blank=True, null=True)), | ||
('commentreceiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments_received', to='dashboard.Profile')), | ||
('commentsender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments_given', to='dashboard.Profile')), | ||
('fulfillment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='dashboard.BountyFulfillment')), | ||
], | ||
options={ | ||
'abstract': False, | ||
}, | ||
), | ||
migrations.CreateModel( | ||
name='FeedbackEntry', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_on', models.DateTimeField(db_index=True, default=economy.models.get_time)), | ||
('modified_on', models.DateTimeField(default=economy.models.get_time)), | ||
('rating', models.SmallIntegerField(blank=True, default=0)), | ||
('comment', models.TextField(blank=True, default='')), | ||
('feedbackType', models.TextField(blank=True, default='', max_length=20)), | ||
('bounty', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks', to='dashboard.Bounty')), | ||
('receiver_profile', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks_got', to='dashboard.Profile')), | ||
('sender_profile', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feedbacks_sent', to='dashboard.Profile')), | ||
], | ||
options={ | ||
'abstract': False, | ||
}, | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Generated by Django 2.1.4 on 2019-01-11 00:49 | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('dashboard', '0007_bountycomment_feedbackentry'), | ||
] | ||
|
||
operations = [ | ||
migrations.RemoveField( | ||
model_name='bountycomment', | ||
name='commentreceiver', | ||
), | ||
migrations.RemoveField( | ||
model_name='bountycomment', | ||
name='commentsender', | ||
), | ||
migrations.RemoveField( | ||
model_name='bountycomment', | ||
name='fulfillment', | ||
), | ||
migrations.DeleteModel( | ||
name='BountyComment', | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1025,7 +1025,6 @@ def submitted(self): | |
"""Exclude results that have not been submitted.""" | ||
return self.exclude(fulfiller_address='0x0000000000000000000000000000000000000000') | ||
|
||
|
||
class BountyFulfillment(SuperModel): | ||
"""The structure of a fulfillment on a Bounty.""" | ||
|
||
|
@@ -2802,3 +2801,34 @@ class BlockedUser(SuperModel): | |
def __str__(self): | ||
"""Return the string representation of a Bounty.""" | ||
return f'<BlockedUser: {self.handle}>' | ||
|
||
|
||
class FeedbackEntry(SuperModel): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. E302 expected 2 blank lines, found 1 |
||
bounty = models.ForeignKey( | ||
'dashboard.Bounty', | ||
related_name='feedbacks', | ||
on_delete=models.CASCADE, | ||
blank=True, | ||
null=True | ||
) | ||
sender_profile = models.ForeignKey( | ||
'dashboard.Profile', | ||
related_name='feedbacks_sent', | ||
on_delete=models.CASCADE, | ||
blank=True, | ||
null=True | ||
) | ||
receiver_profile = models.ForeignKey( | ||
'dashboard.Profile', | ||
related_name='feedbacks_got', | ||
on_delete=models.CASCADE, | ||
blank=True, | ||
null=True | ||
) | ||
rating = models.SmallIntegerField(blank=True, default=0) | ||
comment = models.TextField(default='', blank=True) | ||
feedbackType = models.TextField(default='', blank=True, max_length=20) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like there are only two types of feedback: |
||
|
||
def __str__(self): | ||
"""Return the string representation of a Bounty.""" | ||
return f'<Feedback Bounty #{self.bounty} - from: {self.sender_profile} to: {self.receiver_profile}>' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about changing the naming here to just
comment
since the post is implied as we're creating a comment resource?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, can do.