Projet

Général

Profil

0001-api-new-formdef-popularity-count-method-47889.patch

Lauréline Guérin, 07 décembre 2020 09:53

Télécharger (8,61 ko)

Voir les différences:

Subject: [PATCH] api: new formdef popularity count method (#47889)

 tests/test_api.py | 37 +++++++++++++++++++++++++++++++++++++
 wcs/api.py        | 27 +++++++++++++++++++++++++--
 wcs/sql.py        | 39 ++++++++++++++++++++++++++++++++-------
 3 files changed, 94 insertions(+), 9 deletions(-)
tests/test_api.py
420 420
    assert resp1.json['err'] == 0
421 421
    assert len(resp1.json['data']) == 0
422 422

  
423
    formdef.data_class().wipe()
424

  
425
    # a draft
426
    formdata = formdef.data_class()()
427
    formdata.data = {}
428
    formdata.just_created()
429
    formdata.status = 'draft'
430
    formdata.store()
431

  
432
    other_formdef = FormDef()
433
    other_formdef.name = 'test 2'
434
    other_formdef.fields = []
435
    other_formdef.store()
436
    other_formdata = other_formdef.data_class()()
437
    other_formdata.data = {}
438
    other_formdata.just_created()
439
    other_formdata.store()
440

  
441
    # formdata created:
442
    # - 1 day ago (=3*4)
443
    # - 7 days ago (=2*2)
444
    # - 29 days ago (=1*1)
445
    # - 31 days ago (=0)
446
    for days in [1, 1, 1, 7, 7, 29, 31]:
447
        formdata = formdef.data_class()()
448
        formdata.data = {}
449
        formdata.just_created()
450
        formdata.receipt_time = (datetime.datetime.now() - datetime.timedelta(days=days)).timetuple()
451
        formdata.store()
452

  
453
    resp = get_app(pub).get(sign_uri('/api/formdefs/?include-count=on'))
454
    if not pub.is_using_postgresql():
455
        assert resp.json['data'][0]['count'] == 8
456
    else:
457
        # 3*4 + 2*2 + 1*1
458
        assert resp.json['data'][0]['count'] == 17
459

  
423 460

  
424 461
def test_limited_formdef_list(pub, local_user):
425 462
    Role.wipe()
wcs/api.py
14 14
# You should have received a copy of the GNU General Public License
15 15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import datetime
17 18
import json
18 19
import re
19 20
import time
20 21

  
21 22
from quixote import get_request, get_publisher, get_response, get_session
22
from quixote.errors import MethodNotAllowedError, QueryError
23
from quixote.errors import MethodNotAllowedError
23 24
from quixote.directory import Directory
24 25

  
25 26
from django.utils.encoding import force_text
......
573 574
            if include_count:
574 575
                # we include the count of submitted forms so it's possible to sort
575 576
                # them by "popularity"
576
                formdict['count'] = formdef.data_class().count()
577
                if get_publisher().is_using_postgresql():
578
                    from wcs import sql
579
                    # 4 * number of submitted forms of last 2 days
580
                    # + 2 * number of submitted forms of last 8 days
581
                    # + 1 * number of submitted forms of last 30 days
582
                    # exclude drafts
583
                    criterias = [Equal('formdef_id', formdef.id), NotEqual('status', 'draft')]
584
                    d_now = datetime.datetime.now()
585
                    count = 4 * sql.get_period_total(
586
                        period_start=d_now - datetime.timedelta(days=2), include_start=True,
587
                        criterias=criterias)
588
                    count += 2 * sql.get_period_total(
589
                        period_start=d_now - datetime.timedelta(days=8), include_start=True,
590
                        period_end=d_now - datetime.timedelta(days=2), include_end=False,
591
                        criterias=criterias)
592
                    count += sql.get_period_total(
593
                        period_start=d_now - datetime.timedelta(days=30), include_start=True,
594
                        period_end=d_now - datetime.timedelta(days=8), include_end=False,
595
                        criterias=criterias)
596
                else:
597
                    # naive count
598
                    count = formdef.data_class().count()
599
                formdict['count'] = count
577 600

  
578 601
            formdict['functions'] = {}
579 602
            formdef_workflow_roles = formdef.workflow_roles or {}
wcs/sql.py
2525 2525
            formdatas[0].load_all_evolutions(formdatas)
2526 2526

  
2527 2527

  
2528
def get_period_query(period_start=None, period_end=None, criterias=None, parameters=None):
2528
def get_period_query(period_start=None, include_start=True, period_end=None, include_end=True, criterias=None, parameters=None):
2529 2529
    clause = [NotNull('receipt_time')]
2530 2530
    table_name = 'wcs_all_forms'
2531 2531
    if criterias:
......
2539 2539
                continue
2540 2540
            clause.append(criteria)
2541 2541
    if period_start:
2542
        clause.append(GreaterOrEqual('receipt_time', period_start))
2542
        if include_start:
2543
            clause.append(GreaterOrEqual('receipt_time', period_start))
2544
        else:
2545
            clause.append(Greater('receipt_time', period_start))
2543 2546
    if period_end:
2544
        clause.append(LessOrEqual('receipt_time', period_end))
2547
        if include_end:
2548
            clause.append(LessOrEqual('receipt_time', period_end))
2549
        else:
2550
            clause.append(Less('receipt_time', period_end))
2545 2551
    where_clauses, params, func_clause = parse_clause(clause)
2546 2552
    parameters.update(params)
2547 2553
    statement = ' FROM %s ' % table_name
......
2589 2595
    conn, cur = get_connection_and_cursor()
2590 2596
    statement = '''SELECT DATE_PART('dow', receipt_time) AS weekday, COUNT(*)'''
2591 2597
    parameters = {}
2592
    statement += get_period_query(period_start, period_end, criterias, parameters)
2598
    statement += get_period_query(period_start=period_start, period_end=period_end, criterias=criterias, parameters=parameters)
2593 2599
    statement += ' GROUP BY weekday ORDER BY weekday'''
2594 2600
    cur.execute(statement, parameters)
2595 2601

  
......
2612 2618
    conn, cur = get_connection_and_cursor()
2613 2619
    statement = '''SELECT DATE_PART('hour', receipt_time) AS hour, COUNT(*)'''
2614 2620
    parameters = {}
2615
    statement += get_period_query(period_start, period_end, criterias, parameters)
2621
    statement += get_period_query(period_start=period_start, period_end=period_end, criterias=criterias, parameters=parameters)
2616 2622
    statement += ' GROUP BY hour ORDER BY hour'
2617 2623
    cur.execute(statement, parameters)
2618 2624

  
......
2636 2642
    conn, cur = get_connection_and_cursor()
2637 2643
    statement = '''SELECT DATE_TRUNC('month', receipt_time) AS month, COUNT(*) '''
2638 2644
    parameters = {}
2639
    statement += get_period_query(period_start, period_end, criterias, parameters)
2645
    statement += get_period_query(period_start=period_start, period_end=period_end, criterias=criterias, parameters=parameters)
2640 2646
    statement += ' GROUP BY month ORDER BY month'''
2641 2647
    cur.execute(statement, parameters)
2642 2648

  
......
2665 2671
    conn, cur = get_connection_and_cursor()
2666 2672
    statement = '''SELECT DATE_TRUNC('year', receipt_time) AS year, COUNT(*)'''
2667 2673
    parameters = {}
2668
    statement += get_period_query(period_start, period_end, criterias, parameters)
2674
    statement += get_period_query(period_start=period_start, period_end=period_end, criterias=criterias, parameters=parameters)
2669 2675
    statement += ' GROUP BY year ORDER BY year'
2670 2676
    cur.execute(statement, parameters)
2671 2677

  
......
2688 2694
    return result
2689 2695

  
2690 2696

  
2697
@guard_postgres
2698
def get_period_total(period_start=None, include_start=True, period_end=None, include_end=True, criterias=None):
2699
    conn, cur = get_connection_and_cursor()
2700
    statement = '''SELECT COUNT(*)'''
2701
    parameters = {}
2702
    statement += get_period_query(
2703
        period_start=period_start, include_start=include_start,
2704
        period_end=period_end, include_end=include_end,
2705
        criterias=criterias, parameters=parameters)
2706
    cur.execute(statement, parameters)
2707

  
2708
    result = int(cur.fetchone()[0])
2709

  
2710
    conn.commit()
2711
    cur.close()
2712

  
2713
    return result
2714

  
2715

  
2691 2716
# latest migration, number + description (description is not used
2692 2717
# programmaticaly but will make sure git conflicts if two migrations are
2693 2718
# separately added with the same number)
2694
-