diff --git a/etc/default_data.json b/etc/default_data.json index f5c7e0b7f..594fbf625 100644 --- a/etc/default_data.json +++ b/etc/default_data.json @@ -551,7 +551,7 @@ "launchpad_id": "anteaya", "companies": [ { - "company_name": "independent", + "company_name": "*independent", "end_date": "2013-Apr-02" }, { diff --git a/stackalytics/dashboard/parameters.py b/stackalytics/dashboard/parameters.py index 5b59bf98a..b5e92bf37 100644 --- a/stackalytics/dashboard/parameters.py +++ b/stackalytics/dashboard/parameters.py @@ -69,7 +69,7 @@ def get_default(param_name): if 'release' not in DEFAULTS: release = cfg.CONF.default_release if not release: - runtime_storage_inst = vault.get_vault()['runtime_storage'] + runtime_storage_inst = vault.get_runtime_storage() releases = runtime_storage_inst.get_by_key('releases') if releases: release = releases[-1]['release_name'] diff --git a/stackalytics/dashboard/reports.py b/stackalytics/dashboard/reports.py index 28a6a2c4f..a2200faf9 100644 --- a/stackalytics/dashboard/reports.py +++ b/stackalytics/dashboard/reports.py @@ -159,6 +159,22 @@ def members(): } +@blueprint.route('/affiliation_changes') +@decorators.exception_handler() +@decorators.templated() +def affiliation_changes(): + start_days = str(flask.request.args.get('start_days') or + utils.timestamp_to_date(int(time.time()) - + 365 * 24 * 60 * 60)) + end_days = str(flask.request.args.get('end_days') or + utils.timestamp_to_date(int(time.time()))) + + return { + 'start_days': start_days, + 'end_days': end_days, + } + + @blueprint.route('/cores') @decorators.exception_handler() @decorators.templated() diff --git a/stackalytics/dashboard/templates/reports/affiliation_changes.html b/stackalytics/dashboard/templates/reports/affiliation_changes.html new file mode 100644 index 000000000..cbb8234c3 --- /dev/null +++ b/stackalytics/dashboard/templates/reports/affiliation_changes.html @@ -0,0 +1,162 @@ +{% extends "reports/base_report.html" %} + +{% block title %} +Company Affiliation Changes +{% endblock %} + +{% block scripts %} + + +{% endblock %} + +{% block content %} +

Company Affiliation Changes

+ +

Start of the period:   End of the period:

+ +
+ + + + + + + + + + + +
FromToCountUsers
+
+ +{% endblock %} diff --git a/stackalytics/dashboard/vault.py b/stackalytics/dashboard/vault.py index 7ac30831e..15a2bccee 100644 --- a/stackalytics/dashboard/vault.py +++ b/stackalytics/dashboard/vault.py @@ -68,7 +68,7 @@ def compact_records(records): def extend_record(record): - runtime_storage_inst = get_vault()['runtime_storage'] + runtime_storage_inst = get_runtime_storage() return runtime_storage_inst.get_by_key( runtime_storage_inst._get_record_name(record.record_id)) @@ -121,6 +121,10 @@ def get_memory_storage(): return get_vault()['memory_storage'] +def get_runtime_storage(): + return get_vault()['runtime_storage'] + + def _init_releases(vault): runtime_storage_inst = vault['runtime_storage'] releases = runtime_storage_inst.get_by_key('releases') @@ -170,7 +174,7 @@ def get_project_types(): def get_release_options(): - runtime_storage_inst = get_vault()['runtime_storage'] + runtime_storage_inst = get_runtime_storage() releases = (runtime_storage_inst.get_by_key('releases') or [None])[1:] releases.append({'release_name': 'all'}) releases.reverse() @@ -195,7 +199,7 @@ def get_project_type(project_type_id): def get_user_from_runtime_storage(user_id): - runtime_storage_inst = get_vault()['runtime_storage'] + runtime_storage_inst = get_runtime_storage() user_index = get_vault()['user_index'] if user_id not in user_index: user_index[user_id] = user_processor.load_user( diff --git a/stackalytics/dashboard/web.py b/stackalytics/dashboard/web.py index ba0a0d76d..66fde1110 100644 --- a/stackalytics/dashboard/web.py +++ b/stackalytics/dashboard/web.py @@ -490,6 +490,52 @@ def get_project_types_json(**kwargs): parameters.get_default('project_type')) +@app.route('/api/1.0/affiliation_changes') +@decorators.exception_handler() +@decorators.response() +@decorators.jsonify('affiliation_changes') +def get_company_changes(**kwargs): + + start_days = str(flask.request.args.get('start_days') or + utils.timestamp_to_date(int(time.time()) - + 365 * 24 * 60 * 60)) + end_days = str(flask.request.args.get('end_days') or + utils.timestamp_to_date(int(time.time()))) + + start_date = utils.date_to_timestamp_ext(start_days) + end_date = utils.date_to_timestamp_ext(end_days) + + runtime_storage = vault.get_runtime_storage() + result = [] + + for user in runtime_storage.get_all_users(): + companies = user.get('companies') or [] + if len(companies) < 2: + continue + + companies_iter = iter(companies) + company = companies_iter.next() + old_company_name = company['company_name'] + date = company['end_date'] + + for company in companies_iter: + new_company_name = company['company_name'] + + if start_date <= date <= end_date: + result.append({ + 'user_id': user['user_id'], + 'user_name': user['user_name'], + 'old_company_name': old_company_name, + 'new_company_name': new_company_name, + 'date': date, + }) + + old_company_name = new_company_name + date = company['end_date'] + + return result + + def _get_week(kwargs, param_name): date_param = parameters.get_single_parameter(kwargs, param_name) if date_param: diff --git a/stackalytics/processor/utils.py b/stackalytics/processor/utils.py index c9a0884b6..692751120 100644 --- a/stackalytics/processor/utils.py +++ b/stackalytics/processor/utils.py @@ -57,6 +57,11 @@ def iso8601_to_timestamp(s): return int(time.mktime(iso8601.parse_date(s).timetuple())) +def timestamp_to_date(timestamp): + return (datetime.datetime.fromtimestamp(timestamp). + strftime('%Y-%b-%d')) + + def timestamp_to_week(timestamp): # Jan 4th 1970 is the first Sunday in the Epoch return (timestamp - 3 * 24 * 3600) // (7 * 24 * 3600)