Skip to content

Commit

Permalink
RDISCROWD-4871: Add assigned users column under task browse (#800)
Browse files Browse the repository at this point in the history
* Add assigned users column under task browse

* add tests

* update themes sha to main
  • Loading branch information
dchhabda committed Dec 23, 2022
1 parent a66d296 commit c3f51db
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 13 deletions.
30 changes: 20 additions & 10 deletions pybossa/cache/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import pybossa.app_settings as app_settings
from pybossa.redis_lock import get_locked_tasks_project
from pybossa.util import get_taskrun_date_range_sql_clause_params
from pybossa.cache.task_browse_helpers import get_users_fullnames_from_emails

import heapq

Expand Down Expand Up @@ -85,15 +86,21 @@ def format_task(row, lock_users=[]):
lock_users=lock_users,
available=False)
task['pct_status'] = _pct_status(row.n_task_runs, row.n_answers)
if args and "display_columns" in args and "assigned_users" in args["display_columns"] and row.user_pref:
task["assigned_users"] = row.user_pref.get("assign_user", [])
return task

def format_task_dates(task):
"""convert created and finish date utc to est."""
def format_current_page(task):
# format current page. convert created and finish date utc to est.
# convert assign users from email address to full names.
task["created"] = format_date(task["created"])
task["finish_time"] = format_date(task["finish_time"])
if "assigned_users" in task:
task["assigned_users"] = get_users_fullnames_from_emails(task["assigned_users"])

def search_lock_status_sorting_result():
tasks = []
sql_order = " ORDER BY {} "
sql_order_by = sorting[order_by]


Expand Down Expand Up @@ -182,8 +189,11 @@ def search_lock_status_sorting_result():

params["assign_user"] = args["sql_params"]["assign_user"]

all_available_tasks_sql = sql + filters +\
" ORDER BY %s" % (args.get('order_by') or 'priority_0 desc')
order_by = args.get('order_by') or "priority_0 DESC"
order_by = order_by.replace("assigned_users", "task.user_pref->>'assign_user'")
sql_order = f" ORDER BY {order_by} "

all_available_tasks_sql = sql + filters + sql_order
all_available_tasks = [row for row in session.execute(text(all_available_tasks_sql), params)]

task_reserve_filter = args.get("filter_by_wfilter_upref", {}).get("reserve_filter", "")
Expand Down Expand Up @@ -220,7 +230,7 @@ def search_lock_status_sorting_result():
# format current page task dates utc to est
# this is to obtain 10x better response time
for task in tasks:
format_task_dates(task)
format_current_page(task)

else:
# construct task browse page for owners/admins
Expand All @@ -240,7 +250,6 @@ def search_lock_status_sorting_result():
locked_task_ids = [lock["task_id"] for lock in get_locked_tasks_project(project_id)]
sql_lock_filter = " AND id IN ({})".format(",".join(locked_task_ids))
sql_unlock_filter = " AND id NOT IN ({})".format(",".join(locked_task_ids))
sql_order = " ORDER BY {} "
sql_limit_offset = " LIMIT :limit OFFSET :offset "
params["limit"] = limit
params["offset"] = offset
Expand All @@ -250,9 +259,10 @@ def search_lock_status_sorting_result():
else:
# if not sort by lock_status or locked_tasks_in_project is empty/None,
# sort by the column "order_by"
order_by = args.get('order_by')
sql_order_by = order_by or 'id ASC'
sql_query = sql + sql_order.format(sql_order_by) + sql_limit_offset
order_by = args.get('order_by') or "id ASC"
order_by = order_by.replace("assigned_users", "task.user_pref->>'assign_user'")
sql_order = f" ORDER BY {order_by} "
sql_query = sql + sql_order + sql_limit_offset

results = session.execute(text(sql_query), params)
tasks = [format_task(row, locked_tasks_in_project.get(row.id, [])) for row in results]
Expand All @@ -261,7 +271,7 @@ def search_lock_status_sorting_result():
# this is to obtain 10x better response time
num_tasks = min(len(tasks), 100)
for i in range(num_tasks):
format_task_dates(tasks[i])
format_current_page(tasks[i])
session.execute("RESET enable_indexscan;")

return total_count, tasks
Expand Down
38 changes: 37 additions & 1 deletion pybossa/cache/task_browse_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"!=": operator.ne,
}

users_emails_to_fullnames = {}

def get_task_filters(args):
"""
Expand Down Expand Up @@ -199,7 +200,8 @@ def get_searchable_columns(project_id):
'created': 'task.created',
'filter_by_field': 'filter_by_field',
'lock_status': 'lock_status',
'completed_by': 'completed_by'
'completed_by': 'completed_by',
'assigned_users': 'assigned_users'
}


Expand Down Expand Up @@ -293,6 +295,7 @@ def parse_tasks_browse_args(args):

return parsed_args


def parse_tasks_browse_order_by_args(order_by, display_info_columns):
order_by_result = None
order_by_dict = dict()
Expand Down Expand Up @@ -323,6 +326,7 @@ def parse_tasks_browse_order_by_args(order_by, display_info_columns):

return (order_by_result, order_by_dict)


def validate_user_preferences(user_pref):
if not isinstance(user_pref, dict) or \
not all(x in ['languages', 'locations'] for x in user_pref.keys()):
Expand Down Expand Up @@ -373,6 +377,7 @@ def user_meet_task_requirement(task_id, user_filter, user_profile):
return False
return True


def get_task_preference_score(task_pref, user_profile):
score = 0
for key, value in task_pref.items():
Expand All @@ -384,3 +389,34 @@ def get_task_preference_score(task_pref, user_profile):
# TODO: when user profile is not number, we need another method to calculate score
pass
return score


def get_user_fullname_from_email(email_addr):
# search user by email address in local
# cache users_emails_to_fullnames first
# look for user in db if not found in cache
# with user not found in db, return their email address
# that would be useful for correcting wrong email addresses.
from pybossa.core import user_repo

if email_addr in users_emails_to_fullnames:
return users_emails_to_fullnames[email_addr]

user_fullname = email_addr # missing user info will replace fullname with their email address
user = user_repo.get_by(email_addr=email_addr)
if user:
user_fullname = user.fullname
users_emails_to_fullnames[email_addr] = user_fullname
return user_fullname


def get_users_fullnames_from_emails(emails):
# given list of user emails as an input,
# obtain user full names, sort and return
# full names as comma separated string
users_fullnames = []
for email_addr in emails:
user_fullname = get_user_fullname_from_email(email_addr)
users_fullnames.append(user_fullname)
users_fullnames.sort()
return ", ".join(users_fullnames)
2 changes: 1 addition & 1 deletion pybossa/themes/default
21 changes: 20 additions & 1 deletion test/test_cache/test_cache_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from test import Test, with_context, with_request_context
from pybossa.cache import projects as cached_projects
from test.factories import UserFactory, ProjectFactory, TaskFactory, \
TaskRunFactory, AnonymousTaskRunFactory
TaskRunFactory, AnonymousTaskRunFactory, UserFactory
from unittest.mock import patch
import datetime
import json
Expand Down Expand Up @@ -929,3 +929,22 @@ def test_browse_completed(self):

assert count == 1
assert cached_tasks[0]['id'] == task.id

@with_context
def test_browse_task_assigned_users(self):
project = ProjectFactory.create()
user_pref = dict(assign_user=["y@def.com", "z@ijk.com", "x@abc.com"])
tasks = TaskFactory.create_batch(1, project=project, info={}, n_answers=2, user_pref=user_pref)
TaskRunFactory.create_batch(3, task=tasks[0])
user_x = UserFactory.create(email_addr="x@abc.com", fullname="user_x at_abc")
user_y = UserFactory.create(email_addr="y@def.com", fullname="user_y at_def")

count, cached_tasks = cached_projects.browse_tasks(project.id, {
"display_columns": ["assigned_users"]
})

assert count == 1
assert cached_tasks[0]["id"] == tasks[0].id
assert "assigned_users" in cached_tasks[0], "assigned_users column selected. assigned users should be part of task."
assert "z@ijk.com" in cached_tasks[0]["assigned_users"], "user email to be present for user email not found in the system."
assert cached_tasks[0]["assigned_users"] == "user_x at_abc, user_y at_def, z@ijk.com", "assigned users full names to be present in sorted order."

0 comments on commit c3f51db

Please sign in to comment.