Skip to content

Commit

Permalink
Start/Stop history
Browse files Browse the repository at this point in the history
  • Loading branch information
darkdarkdragon committed Jun 28, 2018
1 parent be6077b commit 1303006
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 4 deletions.
29 changes: 29 additions & 0 deletions app/assets/v2/js/pages/bounty_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,10 @@ var pull_bounty_from_api = function() {


var render_activity = function(result) {
var activity_names = {
work_started: gettext('Work Started'),
work_stopped: gettext('Work Stopped')
};
var activities = [];

if (result.fulfillments) {
Expand Down Expand Up @@ -896,10 +900,35 @@ var render_activity = function(result) {
});
}

if (result.activities) {
result.activities.forEach(function(_activity) {
activities.push({
profileId: _activity.profile.id,
name: _activity.profile.handle,
// text: _activity.pending ? gettext('Worker Applied') : gettext('Work Started'),
text: activity_names[_activity.activity_type],
created_on: _activity.created,
age: timeDifference(new Date(result['now']), new Date(_activity.created)),
status: _activity.activity_type === 'work_started' ? 'started' : 'stopped',
uninterest_possible: false
});
});
}

activities = activities.slice().sort(function(a, b) {
return a['created_on'] < b['created_on'] ? -1 : 1;
}).reverse();

if (activities.length > 1) {
var a1 = activities[0];
var a2 = activities[1];

if (a1.profileId === a2.profileId && a1.status === a2.status && a2.status === 'started' &&
a1.text == a2.text) {
activities.splice(1, 1);
}
}

var html = '<div class="row box activity"><div class="col-12 empty"><p>' + gettext('There\'s no activity yet!') + '</p></div></div>';

if (activities.length > 0) {
Expand Down
24 changes: 24 additions & 0 deletions app/dashboard/migrations/0085_activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 2.0.6 on 2018-06-10 14:28

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


class Migration(migrations.Migration):

dependencies = [
('dashboard', '0084_auto_20180604_1723'),
]

operations = [
migrations.CreateModel(
name='Activity',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('activity_type', models.CharField(blank=True, choices=[('work_started', 'Work started'), ('work_stopped', 'Work stopped')], max_length=50)),
('bounty', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='dashboard.Bounty')),
('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='dashboard.Profile')),
],
),
]
23 changes: 23 additions & 0 deletions app/dashboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,29 @@ def psave_interest(sender, instance, **kwargs):
bounty.save()


class Activity(models.Model):
"""Represent Start work/Stop work event.
Attributes:
ACTIVITY_TYPES (list of tuples): The valid activity types.
"""

ACTIVITY_TYPES = [
('work_started', 'Work Started'),
('work_stopped', 'Work Stopped'),
]
profile = models.ForeignKey('dashboard.Profile', related_name='activities', on_delete=models.CASCADE)
bounty = models.ForeignKey(Bounty, related_name='activities', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True, blank=True, null=True)
activity_type = models.CharField(max_length=50, choices=ACTIVITY_TYPES, blank=True)

def __str__(self):
"""Define the string representation of an interested profile."""
return f"{self.profile.handle} type: {self.activity_type}" \
f"created: {naturalday(self.created_on)}"


class Profile(SuperModel):
"""Define the structure of the user profile.
Expand Down
17 changes: 15 additions & 2 deletions app/dashboard/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import django_filters.rest_framework
from rest_framework import routers, serializers, viewsets

from .models import Bounty, BountyFulfillment, Interest, ProfileSerializer
from .models import Activity, Bounty, BountyFulfillment, Interest, ProfileSerializer


class BountyFulfillmentSerializer(serializers.ModelSerializer):
Expand All @@ -50,12 +50,25 @@ class Meta:
fields = ('profile', 'created', 'pending')


class ActivitySerializer(serializers.ModelSerializer):
"""Handle serializing the Activity object."""

profile = ProfileSerializer()

class Meta:
"""Define the activity serializer metadata."""

model = Activity
fields = ('activity_type', 'created', 'profile')


# Serializers define the API representation.
class BountySerializer(serializers.HyperlinkedModelSerializer):
"""Handle serializing the Bounty object."""

fulfillments = BountyFulfillmentSerializer(many=True)
interested = InterestSerializer(many=True)
activities = ActivitySerializer(many=True)
bounty_owner_email = serializers.SerializerMethodField('override_bounty_owner_email')
bounty_owner_name = serializers.SerializerMethodField('override_bounty_owner_name')

Expand All @@ -79,7 +92,7 @@ class Meta:
'bounty_type', 'project_length', 'experience_level',
'github_url', 'github_comments', 'bounty_owner_address',
'bounty_owner_email', 'bounty_owner_github_username', 'bounty_owner_name',
'fulfillments', 'interested', 'is_open', 'expires_date',
'fulfillments', 'interested', 'is_open', 'expires_date', 'activities',
'keywords', 'current_bounty', 'value_in_eth',
'token_value_in_usdt', 'value_in_usdt_now', 'value_in_usdt', 'status', 'now',
'avatar_url', 'value_true', 'issue_description', 'network',
Expand Down
29 changes: 27 additions & 2 deletions app/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@

from .helpers import handle_bounty_views
from .models import (
Bounty, CoinRedemption, CoinRedemptionRequest, Interest, Profile, ProfileSerializer, Subscription, Tip, Tool,
ToolVote, UserAction,
Activity, Bounty, CoinRedemption, CoinRedemptionRequest, Interest, Profile, ProfileSerializer, Subscription, Tip,
Tool, ToolVote, UserAction,
)
from .notifications import (
maybe_market_tip_to_email, maybe_market_tip_to_github, maybe_market_tip_to_slack, maybe_market_to_github,
Expand Down Expand Up @@ -109,6 +109,28 @@ def record_user_action(user, event_name, instance):
logging.error(f"error in record_action: {e} - {event_name} - {instance}")


def record_bounty_activity(bounty, user, event_name):
kwargs = {
'activity_type': event_name,
'bounty': bounty,
}
if isinstance(user, str):
try:
user = User.objects.get(username=user)
except User.DoesNotExist:
return

if hasattr(user, 'profile'):
kwargs['profile'] = user.profile
else:
return

try:
Activity.objects.create(**kwargs)
except Exception as e:
logging.error(f"error in record_bounty_activity: {e} - {event_name} - {bounty} - {user}")


def helper_handle_access_token(request, access_token):
# https://gist.github.com/owocki/614a18fbfec7a5ed87c97d37de70b110
# interest API via token
Expand All @@ -122,6 +144,7 @@ def create_new_interest_helper(bounty, user, issue_message):
approval_required = bounty.permission_type == 'approval'
acceptance_date = timezone.now() if not approval_required else None
profile_id = user.profile.pk
record_bounty_activity(bounty, user, 'work_started')
interest = Interest.objects.create(
profile_id=profile_id,
issue_message=issue_message,
Expand Down Expand Up @@ -290,6 +313,7 @@ def remove_interest(request, bounty_id):
try:
interest = Interest.objects.get(profile_id=profile_id, bounty=bounty)
record_user_action(request.user, 'stop_work', interest)
record_bounty_activity(bounty, request.user, 'work_stopped')
bounty.interested.remove(interest)
interest.delete()
maybe_market_to_slack(bounty, 'stop_work')
Expand Down Expand Up @@ -360,6 +384,7 @@ def uninterested(request, bounty_id, profile_id):
else:
event_name = "bounty_removed_by_funder"
record_user_action_on_interest(interest, event_name, None)
record_bounty_activity(bounty, interest.profile.user, 'work_stopped')
interest.delete()
except Interest.DoesNotExist:
return JsonResponse({
Expand Down

0 comments on commit 1303006

Please sign in to comment.