• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bloomberg / pybossa / 19114618549

05 Nov 2025 07:59PM UTC coverage: 94.093% (+0.03%) from 94.065%
19114618549

Pull #1069

github

peterkle
add more tests
Pull Request #1069: RDISCROWD-8392 upgrade to boto3

214 of 223 new or added lines in 7 files covered. (95.96%)

152 existing lines in 8 files now uncovered.

17920 of 19045 relevant lines covered (94.09%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.83
/pybossa/cache/users.py
1
# -*- coding: utf8 -*-
2
# This file is part of PYBOSSA.
3
#
4
# Copyright (C) 2017 Scifabric LTD.
5
#
6
# PYBOSSA is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU Affero General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# PYBOSSA is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU Affero General Public License for more details.
15
#
16
# You should have received a copy of the GNU Affero General Public License
17
# along with PYBOSSA.  If not, see <http://www.gnu.org/licenses/>.
18
"""Cache module for users."""
1✔
19
from sqlalchemy.sql import text
1✔
20
from sqlalchemy.exc import ProgrammingError
1✔
21
from pybossa.core import db, timeouts
1✔
22
from pybossa.cache import cache, memoize, delete_memoized, FIVE_MINUTES, \
1✔
23
    ONE_DAY, ONE_WEEK, memoize_with_l2_cache
24
from pybossa.util import pretty_date, exists_materialized_view
1✔
25
from pybossa.model.user import User
1✔
26
from pybossa.cache.projects import overall_progress, n_tasks, n_volunteers
1✔
27
from pybossa.cache.projects import n_total_tasks
1✔
28
from pybossa.model.project import Project
1✔
29
from pybossa.leaderboard.data import get_leaderboard as gl
1✔
30
from pybossa.leaderboard.jobs import leaderboard as lb
1✔
31
import json
1✔
32
from pybossa.util import get_user_pref_db_clause, get_user_filter_db_clause, map_locations
1✔
33
from pybossa.data_access import data_access_levels
1✔
34
from pybossa.util import get_taskrun_date_range_sql_clause_params
1✔
35
from flask import current_app
1✔
36

37
session = db.slave_session
1✔
38

39

40
@memoize_with_l2_cache(timeout=timeouts.get('USER_TIMEOUT'))
1✔
41
def get_leaderboard(n, user_id=None, window=0, info=None):
1✔
42
    """Return the top n users with their rank."""
43
    try:
1✔
44
        return gl(top_users=n, user_id=user_id, window=window, info=info)
1✔
UNCOV
45
    except ProgrammingError:
×
46
        db.session.rollback()
×
47
        lb(info=info)
×
48
        return gl(top_users=n, user_id=user_id, window=window, info=info)
×
49

50

51
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
52
def n_projects_contributed(user_id):
1✔
53
    """Return number of projects user has contributed to."""
54
    sql = text('''
1✔
55
                WITH projects_contributed AS
56
                    (SELECT DISTINCT project_id FROM task_run
57
                    WHERE user_id =:user_id)
58
                SELECT COUNT(*) AS total_projects_contributed
59
                FROM projects_contributed;
60
                ''')
61
    results = session.execute(sql, dict(user_id=user_id))
1✔
62
    total_projects_contributed = 0
1✔
63
    for row in results:
1✔
64
        total_projects_contributed = row.total_projects_contributed
1✔
65
    return total_projects_contributed
1✔
66

67

68
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
69
def get_user_summary(name, current_user=None):
1✔
70
    """Return user summary."""
71
    sql = text('''
1✔
72
               SELECT "user".id, "user".name, "user".fullname, "user".created,
73
               "user".api_key, "user".twitter_user_id, "user".facebook_user_id,
74
               "user".google_user_id, "user".info, "user".admin,
75
               "user".locale,
76
               "user".email_addr, COUNT(task_run.user_id) AS n_answers,
77
               "user".valid_email, "user".confirmation_email_sent,
78
               max(task_run.finish_time) AS last_task_submission_on,
79
               "user".restrict
80
               FROM "user"
81
               LEFT OUTER JOIN task_run ON "user".id=task_run.user_id
82
               WHERE "user".name=:name
83
               GROUP BY "user".id;
84
               ''')
85
    results = session.execute(sql, dict(name=name))
1✔
86
    user = dict()
1✔
87
    for row in results:
1✔
88
        user = dict(id=row.id, name=row.name, fullname=row.fullname,
1✔
89
                    created=row.created, api_key=row.api_key,
90
                    twitter_user_id=row.twitter_user_id,
91
                    google_user_id=row.google_user_id,
92
                    facebook_user_id=row.facebook_user_id,
93
                    info=row.info, admin=row.admin,
94
                    locale=row.locale,
95
                    email_addr=row.email_addr, n_answers=row.n_answers,
96
                    valid_email=row.valid_email,
97
                    confirmation_email_sent=row.confirmation_email_sent,
98
                    registered_ago=pretty_date(row.created),
99
                    last_task_submission_on=row.last_task_submission_on,
100
                    restrict=row.restrict)
101
    if user:
1✔
102
        rank_score = rank_and_score(user['id'])
1✔
103
        user['rank'] = rank_score['rank']
1✔
104
        user['score'] = rank_score['score']
1✔
105
        user['total'] = get_total_users()
1✔
106
        if user['restrict']:
1✔
107
            if (current_user and
1✔
108
                current_user.is_authenticated and
109
               (current_user.id == user['id'])):
110
                return user
1✔
111
            else:
112
                current_app.logger.info("""
1✔
113
                    Method get_user_summary(): User restricted. Returning None as user is not current_user
114
                    for user name %s, user id %s, user restrict %s, current user id %s, current user name %s,
115
                    current user authenticated %s, is_current_user == user %s""",
116
                    name, user.get('id'), user.get('restrict'), current_user.id if current_user else None,
117
                    current_user.name if current_user else None, current_user.is_authenticated if current_user else False,
118
                    current_user.id == user.get('id') if current_user else False)
119
                return None
1✔
120
        else:
121
            return user
1✔
122
    else:
123
        current_app.logger.info("Method get_user_summary(): user is None for user name %s, current user id %s, current user name %s",
1✔
124
            name, current_user.id if current_user else None, current_user.name if current_user else None)
125
        return None
1✔
126

127

128
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
129
def public_get_user_summary(name):
1✔
130
    """Sanitize user summary for public usage"""
131
    private_user = get_user_summary(name)
1✔
132
    public_user = None
1✔
133
    if private_user is not None:
1✔
134
        u = User()
1✔
135
        public_user = u.to_public_json(data=private_user)
1✔
136
    if not public_user:
1✔
137
        current_app.logger.info("Method public_get_user_summary(): public_user is None for user name %s. private_user None = %s",
1✔
138
            name, private_user == None)
139
    return public_user
1✔
140

141

142
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
143
def rank_and_score(user_id):
1✔
144
    """Return rank and score for a user."""
145
    if exists_materialized_view(db, 'users_rank') is False:
1✔
UNCOV
146
        lb()
×
147
    sql = text('''SELECT * from users_rank WHERE id=:user_id''')
1✔
148
    results = session.execute(sql, dict(user_id=user_id))
1✔
149
    rank_and_score = dict(rank=None, score=None)
1✔
150
    for row in results:
1✔
151
        rank_and_score['rank'] = row.rank
1✔
152
        rank_and_score['score'] = row.score
1✔
153
    return rank_and_score
1✔
154

155

156
def projects_contributed(user_id, order_by='name'):
1✔
157
    """Return projects that user_id has contributed to."""
158
    sql = text('''
1✔
159
               WITH projects_contributed as
160
                    (SELECT project_id, MAX(finish_time) as last_contribution  FROM task_run
161
                     WHERE user_id=:user_id GROUP BY project_id)
162
               SELECT project.id, project.name as name, project.short_name, project.owner_id,
163
               project.description, project.info, project.owners_ids
164
               FROM project, projects_contributed
165
               WHERE project.id=projects_contributed.project_id ORDER BY {} DESC;
166
               '''.format(order_by))
167
    results = session.execute(sql, dict(user_id=user_id))
1✔
168
    projects_contributed = []
1✔
169
    for row in results:
1✔
170
        project = dict(id=row.id, name=row.name, short_name=row.short_name,
1✔
171
                       owner_id=row.owner_id,
172
                       owners_ids=row.owners_ids,
173
                       description=row.description,
174
                       overall_progress=overall_progress(row.id),
175
                       n_tasks=n_tasks(row.id),
176
                       n_volunteers=n_volunteers(row.id),
177
                       info=row.info)
178
        projects_contributed.append(project)
1✔
179
    return projects_contributed
1✔
180

181

182
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
183
def projects_contributed_cached(user_id, order_by='name'):
1✔
184
    """Return projects contributed too (cached version)."""
185
    return projects_contributed(user_id, order_by=order_by)
1✔
186

187

188
def public_projects_contributed(user_id):
1✔
189
    """Return projects that user_id has contributed to. Public information only"""
190
    unsanitized_projects = projects_contributed(user_id)
1✔
191
    public_projects = []
1✔
192
    if unsanitized_projects:
1✔
193
        p = Project()
1✔
194
        for project in unsanitized_projects:
1✔
195
            public_project = p.to_public_json(data=project)
1✔
196
            public_projects.append(public_project)
1✔
197
    return public_projects
1✔
198

199

200
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
201
def public_projects_contributed_cached(user_id):
1✔
202
    """Return projects contributed too (cached version)."""
203
    return public_projects_contributed(user_id)
1✔
204

205

206
allowed_project_columns = {
1✔
207
    "created_on": "created",
208
    "project_name": "name"
209
}
210

211

212
def published_projects(user_id, args=None):
1✔
213
    """Return published projects for user_id."""
214
    if args is None:
1✔
215
        args = dict(column=None, order=None)
1✔
216
    sort_args = dict(column=args.get("column"), order=args.get("order"))
1✔
217
    if sort_args.get("order") not in ("asc", "desc"):
1✔
218
        sort_args["order"] = "desc"
1✔
219
    sort_args["column"] = allowed_project_columns.get(sort_args["column"], "created")
1✔
220

221
    sql = text('''
1✔
222
               SELECT project.id, project.name, project.short_name, project.description,
223
               project.owner_id,
224
               project.owners_ids,
225
               project.info
226
               FROM project
227
               WHERE project.published=true
228
               AND :user_id = ANY (project.owners_ids::int[])
229
               order by {column} {order};
230
               '''.format(**sort_args))
231
    projects_published = []
1✔
232
    results = session.execute(sql, dict(user_id=user_id))
1✔
233
    for row in results:
1✔
234
        project = dict(id=row.id, name=row.name, short_name=row.short_name,
1✔
235
                       owner_id=row.owner_id,
236
                       owners_ids=row.owners_ids,
237
                       description=row.description,
238
                       overall_progress=overall_progress(row.id),
239
                       n_tasks=n_tasks(row.id),
240
                       n_volunteers=n_volunteers(row.id),
241
                       info=row.info)
242
        projects_published.append(project)
1✔
243
    return projects_published
1✔
244

245

246
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
247
def published_projects_cached(user_id):
1✔
248
    """Return published projects (cached version)."""
249
    return published_projects(user_id)
1✔
250

251

252
def public_published_projects(user_id):
1✔
253
    """Return projects that user_id has contributed to. Public information only"""
254
    unsanitized_projects = published_projects(user_id)
1✔
255
    public_projects = []
1✔
256
    if unsanitized_projects:
1✔
257
        p = Project()
1✔
258
        for project in unsanitized_projects:
1✔
259
            public_project = p.to_public_json(data=project)
1✔
260
            public_projects.append(public_project)
1✔
261
    return public_projects
1✔
262

263

264
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
265
def public_published_projects_cached(user_id):
1✔
266
    """Return published projects (cached version)."""
267
    return public_published_projects(user_id)
1✔
268

269

270
def draft_projects(user_id):
1✔
271
    """Return draft projects for user_id."""
272
    sql = text('''
1✔
273
               SELECT project.id, project.name, project.short_name, project.description,
274
               project.owner_id,
275
               project.owners_ids,
276
               project.info
277
               FROM project
278
               WHERE project.published=false
279
               AND :user_id = ANY (project.owners_ids::int[]);
280
               ''')
281
    projects_draft = []
1✔
282
    results = session.execute(sql, dict(user_id=user_id))
1✔
283
    for row in results:
1✔
284
        project = dict(id=row.id, name=row.name, short_name=row.short_name,
1✔
285
                       owner_id=row.owner_id,
286
                       owners_ids=row.owners_ids,
287
                       description=row.description,
288
                       overall_progress=overall_progress(row.id),
289
                       n_tasks=n_tasks(row.id),
290
                       n_volunteers=n_volunteers(row.id),
291
                       info=row.info)
292
        projects_draft.append(project)
1✔
293
    return projects_draft
1✔
294

295

296
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
297
def draft_projects_cached(user_id):
1✔
298
    """Return draft projects (cached version)."""
299
    return draft_projects(user_id)
1✔
300

301

302
@cache(timeout=timeouts.get('USER_TOTAL_TIMEOUT'),
1✔
303
       key_prefix="site_total_users")
304
def get_total_users():
1✔
305
    """Return total number of users in the server."""
306
    count = User.query.filter(User.enabled == True).count()
1✔
307
    return count
1✔
308

309

310
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
311
def get_users_page(page, per_page=24):
1✔
312
    """Return users with a paginator."""
313
    offset = (page - 1) * per_page
1✔
314
    sql = text('''SELECT "user".id, "user".name,
1✔
315
               "user".fullname, "user".email_addr,
316
               "user".created, "user".info, COUNT(task_run.id) AS task_runs
317
               FROM task_run, "user"
318
               WHERE "user".id=task_run.user_id GROUP BY "user".id
319
               ORDER BY "user".created DESC LIMIT :limit OFFSET :offset''')
320
    results = session.execute(sql, dict(limit=per_page, offset=offset))
1✔
321
    accounts = []
1✔
322

323
    u = User()
1✔
324

325
    for row in results:
1✔
326
        user = dict(id=row.id, name=row.name, fullname=row.fullname,
1✔
327
                    email_addr=row.email_addr, created=row.created,
328
                    task_runs=row.task_runs, info=row.info,
329
                    registered_ago=pretty_date(row.created))
330
        tmp = u.to_public_json(data=user)
1✔
331
        accounts.append(tmp)
1✔
332
    return accounts
1✔
333

334

335
def delete_user_summary_id(oid):
1✔
336
    """Delete from cache the user summary."""
337
    user = db.session.query(User).get(oid)
1✔
338
    delete_memoized(get_user_summary, user.name)
1✔
339

340

341
def delete_user_summary(name):
1✔
342
    """Delete from cache the user summary."""
343
    delete_memoized(get_user_summary, name)
1✔
344

345

346
@memoize(timeout=timeouts.get('APP_TIMEOUT'))
1✔
347
def get_user_pref_metadata(name):
1✔
348
    sql = text("""
1✔
349
    SELECT info->'metadata', user_pref, info->'data_access' FROM "user" WHERE name=:name;
350
    """)
351
    cursor = session.execute(sql, dict(name=name))
1✔
352
    row = cursor.fetchone()
1✔
353
    upref_mdata = row[0] or {}
1✔
354
    upref_mdata.update(row[1] or {})
1✔
355
    if data_access_levels:
1✔
UNCOV
356
        upref_mdata['data_access'] = row[2] or []
×
357

358
    if 'locations' in upref_mdata:
1✔
359
        map_locations_upref_mdata(upref_mdata)
1✔
360
    return upref_mdata
1✔
361

362

363
def map_locations_upref_mdata(upref_mdata):
1✔
364
    mapped = map_locations(upref_mdata['locations'])
1✔
365

366
    upref_mdata['country_codes'] = mapped['country_codes']
1✔
367
    upref_mdata['country_names'] = mapped['country_names']
1✔
368
    upref_mdata['locations'] = mapped['locations']
1✔
369

370

371
def delete_user_pref_metadata(user):
1✔
372
    delete_memoized(get_user_pref_metadata, user.name)
1✔
373
    delete_memoized(get_user_by_id, user.id)
1✔
374

375

376
@memoize(timeout=timeouts.get('APP_TIMEOUT'))
1✔
377
def get_taskbrowse_bookmarks(name):
1✔
378
    sql = text("""
1✔
379
    SELECT info->'taskbrowse_bookmarks' FROM "user" WHERE name=:name;
380
    """)
381
    cursor = session.execute(sql, dict(name=name))
1✔
382
    row = cursor.fetchone()
1✔
383
    taskbrowse_bookmarks = row[0] or {}
1✔
384
    return taskbrowse_bookmarks
1✔
385

386

387
def delete_taskbrowse_bookmarks(user):
1✔
388
    delete_memoized(get_taskbrowse_bookmarks, user.name)
1✔
389
    delete_memoized(get_user_by_id, user.id)
1✔
390

391

392
def get_user_preferences(user_id):
1✔
393
    user = get_user_by_id(user_id)
1✔
394
    user_pref = user.user_pref or {} if user else {}
1✔
395
    user_email = user.email_addr if user else None
1✔
396
    if 'locations' in user_pref:
1✔
397
        map_locations_upref_mdata(user_pref)
1✔
398
    return get_user_pref_db_clause(user_pref, user_email)
1✔
399

400

401
def get_user_filters(user_id):
1✔
402
    user_profile = get_user_profile_metadata(user_id)
1✔
403
    user_profile = json.loads(user_profile) if user_profile else {}
1✔
404
    return get_user_filter_db_clause(user_profile)
1✔
405

406

407
@memoize(timeout=ONE_DAY)
1✔
408
def get_user_by_id(user_id):
1✔
409
    assert user_id is not None or user_id > 0
1✔
410
    user = User.query.get(user_id)
1✔
411
    return user
1✔
412

413

414
def get_user_profile_metadata(user_id):
1✔
415
    user = get_user_by_id(user_id)
1✔
416
    info = user.info or {} if user else {}
1✔
417
    return info.get("metadata", {}).get('profile')
1✔
418

419

420
def get_user_email(user_id):
1✔
421
    user = get_user_by_id(user_id)
1✔
422
    return user.email_addr if user else None
1✔
423

424

425
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
426
def get_users_for_report():
1✔
427
    """Return information for all users to generate report."""
428
    sql = text("""
1✔
429
        SELECT u.id AS u_id,
430
            name, fullname, email_addr, u.created, admin, enabled, locale,
431
            subadmin, consent, restrict,
432
            user_pref->'languages' AS languages,
433
            user_pref->'locations' AS locations,
434
            u.info->'metadata'->'work_hours_from' AS work_hours_from,
435
            u.info->'metadata'->'work_hours_to' AS work_hours_to,
436
            u.info->'metadata'->'timezone' AS timezone,
437
            u.info->'metadata'->'user_type' AS type_of_user,
438
            u.info->'metadata'->'review' AS additional_comments,
439
            count(t.id) AS completed_task_runs,
440
            min(finish_time) AS first_submission_date,
441
            max(finish_time) AS last_submission_date,
442
            coalesce(
443
                AVG(to_timestamp(finish_time, 'YYYY-MM-DD"T"HH24-MI-SS.US') - to_timestamp(t.created, 'YYYY-MM-DD"T"HH24-MI-SS.US')),
444
                interval '0s') AS avg_time_per_task
445
        FROM "user" u LEFT JOIN task_run t ON u.id = t.user_id
446
        WHERE u.restrict=False AND u.email_addr NOT LIKE 'del-%@del.com'
447
        GROUP BY u.id;
448
    """)
449
    results = session.execute(sql)
1✔
450
    users_report = [ dict(id=row.u_id, name=row.name, fullname=row.fullname,
1✔
451
                    email_addr=row.email_addr, created=row.created, locale=row.locale,
452
                    admin=row.admin, subadmin=row.subadmin, enabled=row.enabled, languages=row.languages,
453
                    locations=row.locations, work_hours_from=row.work_hours_from,
454
                    work_hours_to=row.work_hours_to, timezone=row.timezone,
455
                    additional_comments=row.additional_comments,
456
                    type_of_user=row.type_of_user, first_submission_date=row.first_submission_date,
457
                    last_submission_date=row.last_submission_date,
458
                    completed_task_runs=row.completed_task_runs, avg_time_per_task=str(round(row.avg_time_per_task.total_seconds() / 60, 2)),
459
                    total_projects_contributed=n_projects_contributed(row.u_id),
460
                    percentage_tasks_completed=round(float(row.completed_task_runs) * 100 / n_total_tasks(), 2) if n_total_tasks() else 0,
461
                    consent=row.consent, restrict=row.restrict)
462
                    for row in results]
463
    return users_report
1✔
464

465

466
@memoize(timeout=timeouts.get('APP_TIMEOUT'))
1✔
467
def get_project_report_userdata(project_id, start_date, end_date):
1✔
468
    """Return users details who contributed to a particular project."""
469
    date_clause, sql_params = get_taskrun_date_range_sql_clause_params(start_date, end_date)
1✔
470
    sql_params["project_id"] = project_id
1✔
471
    sql_params["total_tasks"] = n_tasks(project_id)
1✔
472
    sql = text(
1✔
473
            '''
474
            SELECT id as u_id, name, fullname, email_addr, admin, subadmin, enabled,
475
            user_pref->'languages' AS languages, user_pref->'locations' AS locations,
476
            info->'metadata'->'work_hours_from' AS work_hours_from, info->'metadata'->'work_hours_to' AS work_hours_to,
477
            info->'metadata'->'timezone' AS timezone, info->'metadata'->'user_type' AS type_of_user,
478
            info->'metadata'->'review' AS additional_comments,
479
            (SELECT count(id) FROM task_run WHERE user_id = u.id AND project_id=:project_id''' + date_clause +''') AS completed_tasks,
480
            ((SELECT count(id) FROM task_run WHERE user_id = u.id AND project_id =:project_id''' + date_clause +''') * 100 / :total_tasks) AS percent_completed_tasks,
481
            (SELECT min(finish_time) FROM task_run WHERE user_id = u.id AND project_id=:project_id''' + date_clause +''') AS first_submission_date,
482
            (SELECT max(finish_time) FROM task_run WHERE user_id = u.id AND project_id=:project_id''' + date_clause +''') AS last_submission_date,
483
            (SELECT coalesce(AVG(to_timestamp(finish_time, 'YYYY-MM-DD"T"HH24-MI-SS.US') -
484
            to_timestamp(created, 'YYYY-MM-DD"T"HH24-MI-SS.US')), interval '0s')
485
            FROM task_run WHERE user_id = u.id AND project_id=:project_id''' + date_clause +''') AS avg_time_per_task
486
            FROM "user" u WHERE id IN
487
            (SELECT DISTINCT user_id FROM task_run GROUP BY project_id, user_id HAVING project_id=:project_id);
488
            ''')
489
    results = session.execute(sql, sql_params)
1✔
490
    users_report = [
1✔
491
        [row.u_id, row.name, row.fullname, row.email_addr,
492
         row.admin, row.subadmin, row.enabled, row.languages,
493
         row.locations, row.work_hours_from, row.work_hours_to,
494
         row.timezone, row.type_of_user, row.additional_comments,
495
         row.completed_tasks, row.percent_completed_tasks,
496
         row.first_submission_date, row.last_submission_date,
497
         round(row.avg_time_per_task.total_seconds() / 60, 2)]
498
         for row in results]
499
    return users_report
1✔
500

501

502
@memoize(timeout=ONE_WEEK)
1✔
503
def get_user_info(user_id):
1✔
504
    sql = text('''select name, email_addr from "user" where
1✔
505
                  id=:user_id''')
506
    user = session.execute(sql, dict(user_id=user_id)).first()
1✔
507
    return dict(user) if user else None
1✔
508

509

510
@memoize(timeout=timeouts.get('USER_TIMEOUT'))
1✔
511
def get_announcements_by_level_cached(level):
1✔
512
    sql = text('''
1✔
513
        SELECT id, title, body
514
        FROM announcement
515
        WHERE (published = TRUE AND ((info->>'level')::int >= :level))''')
516
    results = session.execute(sql, dict(level=level))
1✔
517
    return [dict(row) for row in results]
1✔
518

519

520
def get_announcements_cached(user, announcement_levels):
1✔
521
    if not (announcement_levels and user and user.is_authenticated):
1✔
522
        return []
1✔
523
    level = announcement_levels['user']['level']
1✔
524
    if user.admin:
1✔
525
        level = announcement_levels['admin']['level']
1✔
526
    elif user.subadmin:
1✔
527
        level = announcement_levels['subadmin']['level']
1✔
528
    return get_announcements_by_level_cached(level)
1✔
529

530

531
def get_users_for_data_access(data_access):
1✔
532
    from pybossa.data_access import get_user_data_access_db_clause
1✔
533

534
    sql = '''select id::text, fullname, email_addr, enabled from "user"'''
1✔
535
    clause = get_user_data_access_db_clause(data_access)
1✔
536
    sql = sql +  '''where {}'''.format(clause) if clause else sql
1✔
537
    results = session.execute(sql).fetchall()
1✔
538
    return [dict(row) for row in results]
1✔
539

540

541
def get_users_access_levels(users):
1✔
542

543
    if not users:
1✔
544
        return []
1✔
545

546
    all(int(u) for u in users)
1✔
547
    users = ', '.join(map(str, users))
1✔
548
    sql = text('''select id, info->'data_access' as data_access from "user"
1✔
549
        where id in({})'''.format(users))
550
    results = session.execute(sql).fetchall()
1✔
551
    return [dict(row) for row in results]
1✔
552

553

554
def delete_published_projects(user_id):
1✔
555
    """Delete from cache the users (un)published project."""
556
    delete_memoized(draft_projects_cached, user_id)
1✔
557
    delete_memoized(published_projects_cached, user_id)
1✔
558

559

560
@memoize(timeout=FIVE_MINUTES)
1✔
561
def get_tasks_completed_between(user_id, beginning_time_utc, end_time_utc=None):
1✔
562
    timestamp_tmpl = 'TO_TIMESTAMP({}, \'YYYY-MM-DD"T"HH24:MI:SS.US\')'
1✔
563
    created_timestamp = timestamp_tmpl.format('created')
1✔
564
    end_time_fragment = ''
1✔
565
    if end_time_utc:
1✔
566
        end_timestamp = timestamp_tmpl.format('\'{}\''.format(end_time_utc))
1✔
567
        end_time_fragment = 'AND {} <= {}'.format(created_timestamp, end_timestamp)
1✔
568
    beginning_timestamp = timestamp_tmpl.format('\'{}\''.format(beginning_time_utc))
1✔
569
    sql = text('''
1✔
570
        SELECT id, created
571
        FROM "task_run"
572
        WHERE user_id = {} AND {} >= {} {}
573
    '''.format(str(user_id), created_timestamp, beginning_timestamp, end_time_fragment))
574
    results = session.execute(sql)
1✔
575
    return [dict(row) for row in results]
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc