def warm_app(id, short_name, featured=False): if id not in apps_cached: cached_apps.get_app(short_name) cached_apps.n_tasks(id) n_task_runs = cached_apps.n_task_runs(id) cached_apps.overall_progress(id) cached_apps.last_activity(id) cached_apps.n_completed_tasks(id) cached_apps.n_volunteers(id) if n_task_runs >= 1000 or featured: print "Getting stats for %s as it has %s task runs" % (short_name, n_task_runs) stats.get_stats(id, app.config.get('GEO')) apps_cached.append(id)
def warm_app(id, short_name, featured=False): if id not in apps_cached: cached_apps.get_app(short_name) cached_apps.n_tasks(id) n_task_runs = cached_apps.n_task_runs(id) cached_apps.overall_progress(id) cached_apps.last_activity(id) cached_apps.n_completed_tasks(id) cached_apps.n_volunteers(id) if n_task_runs >= 1000 or featured: print("Getting stats for %s as it has %s task runs" % (short_name, n_task_runs)) stats.get_stats(id) apps_cached.append(id)
def warm_project(_id, short_name, featured=False): if _id not in projects_cached: cached_projects.get_project(short_name) cached_projects.n_tasks(_id) n_task_runs = cached_projects.n_task_runs(_id) cached_projects.overall_progress(_id) cached_projects.last_activity(_id) cached_projects.n_completed_tasks(_id) cached_projects.n_volunteers(_id) if n_task_runs >= 1000 or featured: # print ("Getting stats for %s as it has %s task runs" % # (short_name, n_task_runs)) stats.get_stats(_id, app.config.get('GEO')) projects_cached.append(_id)
def get_project_stats(_id, short_name): # pragma: no cover """Get stats for project.""" import pybossa.cache.projects as cached_projects import pybossa.cache.project_stats as stats from flask import current_app cached_projects.get_project(short_name) cached_projects.n_tasks(_id) cached_projects.n_task_runs(_id) cached_projects.overall_progress(_id) cached_projects.last_activity(_id) cached_projects.n_completed_tasks(_id) cached_projects.n_volunteers(_id) stats.get_stats(_id, current_app.config.get('GEO'))
def update_stats(project_id, period='2 week'): """Update the stats of a given project.""" hours, hours_anon, hours_auth, max_hours, \ max_hours_anon, max_hours_auth = stats_hours(project_id, period) users, anon_users, auth_users = stats_users(project_id, period) dates, dates_anon, dates_auth = stats_dates(project_id, period) sum(dates.values()) sorted(dates.iteritems(), key=operator.itemgetter(0)) dates_stats = stats_format_dates(project_id, dates, dates_anon, dates_auth) hours_stats = stats_format_hours(project_id, hours, hours_anon, hours_auth, max_hours, max_hours_anon, max_hours_auth) users_stats = stats_format_users(project_id, users, anon_users, auth_users) data = dict(dates_stats=dates_stats, hours_stats=hours_stats, users_stats=users_stats) ps = session.query(ProjectStats).filter_by(project_id=project_id).first() n_tasks = cached_projects.n_tasks(project_id) n_task_runs = cached_projects.n_task_runs(project_id) n_results = cached_projects.n_results(project_id) overall_progress = cached_projects.overall_progress(project_id) last_activity = cached_projects.last_activity(project_id) n_volunteers = cached_projects.n_volunteers(project_id) n_completed_tasks = cached_projects.n_completed_tasks(project_id) average_time = cached_projects.average_contribution_time(project_id) n_blogposts = cached_projects.n_blogposts(project_id) if ps is None: ps = ProjectStats(project_id=project_id, info=data, n_tasks=n_tasks, n_task_runs=n_task_runs, n_results=n_results, n_volunteers=n_volunteers, n_completed_tasks=n_completed_tasks, average_time=average_time, overall_progress=overall_progress, n_blogposts=n_blogposts, last_activity=last_activity) db.session.add(ps) else: ps.info = data ps.n_tasks = n_tasks ps.n_task_runs = n_task_runs ps.overall_progress = overall_progress ps.last_activity = last_activity ps.n_results = n_results ps.n_completed_tasks = n_completed_tasks ps.n_volunteers = n_volunteers ps.average_time = average_time ps.n_blogposts = n_blogposts db.session.commit() return dates_stats, hours_stats, users_stats
def send_email_notifications(): from pybossa.core import sentinel from pybossa.cache import projects as cached_projects from pybossa.core import project_repo from pybossa.sched import Schedulers redis_conn = sentinel.master project_set = redis_conn.hgetall('updated_project_ids') or {} for project_id, timestamp in project_set.iteritems(): project = project_repo.get(project_id) redis_conn.hdel('updated_project_ids', project_id) if not project.email_notif: continue user_emails = [] if cached_projects.get_project_scheduler(project_id) == Schedulers.user_pref: user_emails = user_repo.get_user_pref_recent_contributor_emails(project_id, timestamp) else: if cached_projects.overall_progress(project_id) != 100: user_emails = user_repo.get_recent_contributor_emails(project_id) if user_emails: recipients = [] for email_addr in user_emails: if email_addr not in recipients: recipients.append(email_addr) subject = (u'New Tasks have been imported to {}'.format(project.name)) body = u'Hello,\n\nThere have been new tasks uploaded to the previously finished project, {0}. ' \ u'\nLog on to {1} to complete any available tasks.' \ .format(project.name, current_app.config.get('BRAND')) mail_dict = dict(recipients=recipients, subject=subject, body=body) send_mail(mail_dict) return True
def draft_projects(user_id): """Return draft projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, owner_id, project.info FROM project WHERE project.owner_id=:user_id AND (project.info->>'task_presenter') IS NULL GROUP BY project.id, project.name, project.short_name, project.description; ''') projects_draft = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_draft.append(project) return projects_draft
def hidden_projects(user_id): """Return hidden projects for user_id.""" sql = text( """ SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.info FROM project, task WHERE project.id=task.project_id AND project.owner_id=:user_id AND project.hidden=1 AND (project.info->>'task_presenter') IS NOT NULL GROUP BY project.id, project.name, project.short_name, project.description;""" ) projects_published = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict( id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info, ) projects_published.append(project) return projects_published
def projects_contributed(user_id): """Return projects that user_id has contributed to.""" sql = text( """ WITH apps_contributed as (SELECT DISTINCT(project_id) FROM task_run WHERE user_id=:user_id) SELECT project.id, project.name, project.short_name, project.owner_id, project.description, project.info FROM project, apps_contributed WHERE project.id=apps_contributed.project_id ORDER BY project.name DESC; """ ) results = session.execute(sql, dict(user_id=user_id)) projects_contributed = [] for row in results: project = dict( id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info, ) projects_contributed.append(project) return projects_contributed
def projects_contributed(user_id, order_by='name'): """Return projects that user_id has contributed to.""" sql = text(''' WITH projects_contributed as (SELECT project_id, MAX(finish_time) as last_contribution FROM task_run WHERE user_id=:user_id GROUP BY project_id) SELECT project.id, project.name as name, project.short_name, project.owner_id, project.description, project.info, project.owners_ids FROM project, projects_contributed WHERE project.id=projects_contributed.project_id ORDER BY {} DESC; '''.format(order_by)) results = session.execute(sql, dict(user_id=user_id)) projects_contributed = [] for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, owners_ids=row.owners_ids, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_contributed.append(project) return projects_contributed
def get_enhanced_volumes(category): """Return the categories volumes enhanced with project data.""" volumes = category.info.get('volumes', []) projects = project_repo.filter_by(category_id=category.id) for volume in volumes: vol_projects = [ dict(id=p.id, name=p.name, short_name=p.short_name, published=p.published, overall_progress=overall_progress(p.id)) for p in projects if p.info.get('volume_id') == volume['id'] ] completed_projects = [ p for p in vol_projects if p['overall_progress'] == 100 ] ongoing_projects = [ p for p in vol_projects if p['published'] and p not in completed_projects ] volume['projects'] = vol_projects volume['n_completed_projects'] = len(completed_projects) volume['n_ongoing_projects'] = len(ongoing_projects) return volumes
def hidden_projects(user_id): """Return hidden projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.info FROM project, task WHERE project.id=task.project_id AND project.owner_id=:user_id AND project.hidden=1 AND project.info LIKE('%task_presenter%') GROUP BY project.id, project.name, project.short_name, project.description, project.info;''') projects_published = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=json.loads(row.info)) projects_published.append(project) return projects_published
def published_projects(user_id, args=None): """Return published projects for user_id.""" if args is None: args = dict(column=None, order=None) sort_args = dict(column=args.get("column"), order=args.get("order")) if sort_args.get("order") not in ("asc", "desc"): sort_args["order"] = "desc" sort_args["column"] = allowed_project_columns.get(sort_args["column"], "created") sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.owners_ids, project.info FROM project WHERE project.published=true AND :user_id = ANY (project.owners_ids::int[]) order by {column} {order}; '''.format(**sort_args)) projects_published = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, owners_ids=row.owners_ids, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_published.append(project) return projects_published
def send_email_notifications(): from pybossa.core import sentinel from pybossa.cache import projects as cached_projects from pybossa.core import project_repo redis_conn = sentinel.master project_set = redis_conn.smembers('updated_project_ids') if project_set: for project_id in project_set: project = project_repo.get(project_id) if cached_projects.overall_progress(project_id) != 100 and project.email_notif: user_emails = user_repo.get_recent_contributor_emails(project_id) recipients = [] if user_emails: for email_addr in user_emails: if email_addr not in recipients: recipients.append(email_addr) subject = ('New Tasks have been imported to {}'.format(project.name)) body = "Hello,\n\nThere have been new tasks uploaded to the previously finished project, {0}. " \ "\nLog on to {1} to complete any available tasks." \ .format(project.name, current_app.config.get('BRAND')) mail_dict = dict(recipients=recipients, subject=subject, body=body) send_mail(mail_dict) redis_conn.srem('updated_project_ids', project_id) return True
def update_stats(project_id, period='2 week'): """Update the stats of a given project.""" hours, hours_anon, hours_auth, max_hours, \ max_hours_anon, max_hours_auth = stats_hours(project_id, period) users, anon_users, auth_users = stats_users(project_id, period) dates, dates_anon, dates_auth = stats_dates(project_id, period) sum(dates.values()) sorted(iter(dates.items()), key=operator.itemgetter(0)) dates_stats = stats_format_dates(project_id, dates, dates_anon, dates_auth) hours_stats = stats_format_hours(project_id, hours, hours_anon, hours_auth, max_hours, max_hours_anon, max_hours_auth) users_stats = stats_format_users(project_id, users, anon_users, auth_users) data = dict(dates_stats=dates_stats, hours_stats=hours_stats, users_stats=users_stats) ps = session.query(ProjectStats).filter_by(project_id=project_id).first() n_tasks = cached_projects.n_tasks(project_id) n_task_runs = cached_projects.n_task_runs(project_id) n_results = cached_projects.n_results(project_id) overall_progress = cached_projects.overall_progress(project_id) last_activity = cached_projects.last_activity(project_id) n_volunteers = cached_projects.n_volunteers(project_id) n_completed_tasks = cached_projects.n_completed_tasks(project_id) average_time = cached_projects.average_contribution_time(project_id) n_blogposts = cached_projects.n_blogposts(project_id) if ps is None: ps = ProjectStats(project_id=project_id, info=data, n_tasks=n_tasks, n_task_runs=n_task_runs, n_results=n_results, n_volunteers=n_volunteers, n_completed_tasks=n_completed_tasks, average_time=average_time, overall_progress=overall_progress, n_blogposts=n_blogposts, last_activity=last_activity) db.session.add(ps) else: ps.info = data ps.n_tasks = n_tasks ps.n_task_runs = n_task_runs ps.overall_progress = overall_progress ps.last_activity = last_activity ps.n_results = n_results ps.n_completed_tasks = n_completed_tasks ps.n_volunteers = n_volunteers ps.average_time = average_time ps.n_blogposts = n_blogposts db.session.commit() return dates_stats, hours_stats, users_stats
def draft_projects(user_id): """Return draft projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.owners_ids, project.info FROM project WHERE project.published=false AND :user_id = ANY (project.owners_ids::int[]); ''') projects_draft = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, owners_ids=row.owners_ids, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_draft.append(project) return projects_draft
def before_add_task_event(mapper, conn, target): redis_conn = sentinel.master if cached_projects.get_project_scheduler(target.project_id) == Schedulers.user_pref: if not redis_conn.hget('updated_project_ids', target.project_id): redis_conn.hset('updated_project_ids', target.project_id, make_timestamp()) else: if cached_projects.overall_progress(target.project_id) == 100: redis_conn.hset('updated_project_ids', target.project_id, make_timestamp())
def test_overall_progres_returns_actual_progress_percentage(self): total_tasks = 4 completed_tasks = 2 project = self.create_project_with_tasks( completed_tasks=completed_tasks, ongoing_tasks=total_tasks-completed_tasks) progress = cached_projects.overall_progress(project.id) assert progress == 50, progress
def test_overall_progres_returns_actual_progress_percentage(self): total_tasks = 4 completed_tasks = 2 project = self.create_project_with_tasks( completed_tasks=completed_tasks, ongoing_tasks=total_tasks - completed_tasks) progress = cached_projects.overall_progress(project.id) assert progress == 50, progress
def check_contributing_state(project, user_id=None, user_ip=None): """Return the state of a given project for a given user. Depending on whether the project is completed or not and the user can contribute more to it or not. """ project_id = project['id'] if type(project) == dict else project.id states = ('completed', 'draft', 'can_contribute', 'cannot_contribute') if overall_progress(project_id) >= 100: return states[0] if _has_no_presenter(project) or _has_no_tasks(project_id): return states[1] if n_available_tasks(project_id, user_id=user_id, user_ip=user_ip) > 0: return states[2] return states[3]
def get_stats(project_id, period='2 week', full=False): """Get project's stats.""" ps = session.query(ProjectStats).filter_by(project_id=project_id).first() if not ps: update_stats(project_id, period) ps = session.query(ProjectStats).filter_by( project_id=project_id).first() # stuff we want real-time ps.overall_progress = cached_projects.overall_progress(project_id) ps.n_tasks = cached_projects.n_tasks(project_id) # end if full: return ps else: return ps.info['dates_stats'], ps.info['hours_stats'], ps.info[ 'users_stats']
def draft_projects(user_id): """Return draft projects for user_id.""" sql = text(''' SELECT * FROM project WHERE project.published=false AND :user_id = ANY (project.owners_ids::int[]); ''') projects_draft = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(row) project['n_tasks'] = n_tasks(row.id) project['n_volunteers'] = n_volunteers(row.id) project['overall_progress'] = overall_progress(row.id) projects_draft.append(project) return projects_draft
def projects_contributed(user_id, order_by='name'): """Return projects that user_id has contributed to.""" sql = text(''' WITH projects_contributed as (SELECT project_id, MAX(finish_time) as last_contribution FROM task_run WHERE user_id=:user_id GROUP BY project_id) SELECT * FROM project, projects_contributed WHERE project.id=projects_contributed.project_id ORDER BY {} DESC; '''.format(order_by)) results = session.execute(sql, dict(user_id=user_id)) projects_contributed = [] for row in results: project = dict(row) project['n_tasks'] = n_tasks(row.id) project['n_volunteers'] = n_volunteers(row.id) project['overall_progress'] = overall_progress(row.id) projects_contributed.append(project) return projects_contributed
def projects_contributed(user_id): """Return projects that user_id has contributed to.""" sql = text(''' WITH projects_contributed as (SELECT DISTINCT(project_id) FROM task_run WHERE user_id=:user_id) SELECT * FROM project, projects_contributed WHERE project.id=projects_contributed.project_id ORDER BY project.name DESC; ''') results = session.execute(sql, dict(user_id=user_id)) projects_contributed = [] for row in results: project = dict(row) project['n_tasks'] = n_tasks(row.id) project['n_volunteers'] = n_volunteers(row.id) project['overall_progress'] = overall_progress(row.id), projects_contributed.append(project) return projects_contributed
def draft_projects(user_id): """Return draft projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.info FROM project WHERE project.owner_id=:user_id AND project.published=false; ''') projects_draft = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_draft.append(project) return projects_draft
def projects_contributed(user_id): """Return projects that user_id has contributed to.""" sql = text(''' WITH projects_contributed as (SELECT DISTINCT(project_id) FROM task_run WHERE user_id=:user_id) SELECT project.id, project.name, project.short_name, project.owner_id, project.description, project.info FROM project, projects_contributed WHERE project.id=projects_contributed.project_id ORDER BY project.name DESC; ''') results = session.execute(sql, dict(user_id=user_id)) projects_contributed = [] for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_contributed.append(project) return projects_contributed
def published_projects(user_id): """Return published projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.info FROM project WHERE project.published=true AND project.owner_id=:user_id; ''') projects_published = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=row.info) projects_published.append(project) return projects_published
def get_built_projects(category): """Get template and volume for all built projects in a category. Needed to check which combinations of templates and volumes are still available. Should refactor some of the above to use this query, which is really the core of the additional options for building projects. """ sql = text(""" WITH empty_results AS ( SELECT project.id AS project_id, COUNT(CASE WHEN result.info IS NULL THEN 1 END) FROM project LEFT JOIN result ON project.id = result.project_id GROUP BY project.id ) SELECT project.id, project.info->>'template_id' AS template_id, project.info->>'volume_id' AS volume_id, empty_results.count AS n_empty_results FROM project, empty_results, category WHERE empty_results.project_id = project.id AND category.id = :category_id AND category.id = project.category_id GROUP BY project.id, project.info, empty_results.count; """) session = db.slave_session results = session.execute(sql, dict(category_id=category.id)) return [{ 'project_id': row.id, 'template_id': row.template_id, 'volume_id': row.volume_id, 'overall_progress': overall_progress(row.id), 'empty_results': row.n_empty_results } for row in results]
def published_projects(user_id): """Return published projects for user_id.""" sql = text(''' SELECT project.id, project.name, project.short_name, project.description, project.owner_id, project.info FROM project, task WHERE project.id=task.project_id AND project.owner_id=:user_id AND project.hidden=0 AND project.info LIKE('%task_presenter%') GROUP BY project.id, project.name, project.short_name, project.description, project.info;''') projects_published = [] results = session.execute(sql, dict(user_id=user_id)) for row in results: project = dict(id=row.id, name=row.name, short_name=row.short_name, owner_id=row.owner_id, description=row.description, overall_progress=overall_progress(row.id), n_tasks=n_tasks(row.id), n_volunteers=n_volunteers(row.id), info=json.loads(row.info)) projects_published.append(project) return projects_published
def test_overall_progress_returns_0_if_no_tasks(self): project = ProjectFactory.create() progress = cached_projects.overall_progress(project.id) assert progress == 0, progress
def before_add_task_event(mapper, conn, target): redis_conn = sentinel.master if cached_projects.overall_progress(target.project_id) == 100: redis_conn.sadd('updated_project_ids', target.project_id)