From ee7c18aa7c5c6ee9481b9242ca14b2f1de15d614 Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 21 Feb 2025 15:15:52 +0200 Subject: [PATCH 01/19] ENG-5751 remove old keen logic --- admin/nodes/views.py | 1 - api/nodes/serializers.py | 4 +- .../nodes/serializers/test_serializers.py | 1 - .../commands/cumulative_plos_metrics.py | 91 ---------- osf/models/node.py | 18 +- osf_tests/test_node.py | 2 - ...late_popular_projects_and_registrations.py | 170 +++++++++--------- website/project/utils.py | 73 -------- website/routes.py | 10 -- website/settings/defaults.py | 4 +- website/templates/base.mako | 18 -- 11 files changed, 89 insertions(+), 303 deletions(-) diff --git a/admin/nodes/views.py b/admin/nodes/views.py index 53a5fc54e02..e5503f020bc 100644 --- a/admin/nodes/views.py +++ b/admin/nodes/views.py @@ -649,7 +649,6 @@ def post(self, request, *args, **kwargs): node = self.get_object() node.is_public = False - node.keenio_read_key = '' # After set permissions callback for addon in node.get_addons(): diff --git a/api/nodes/serializers.py b/api/nodes/serializers.py index bef17a795ca..952286707ae 100644 --- a/api/nodes/serializers.py +++ b/api/nodes/serializers.py @@ -11,7 +11,7 @@ NodeFileHyperLinkField, RelationshipField, ShowIfVersion, TargetTypeField, TypeField, WaterbutlerLink, BaseAPISerializer, - HideIfWikiDisabled, ShowIfAdminScopeOrAnonymous, + HideIfWikiDisabled, ValuesListField, TargetField, ) from api.base.settings import ADDONS_FOLDER_CONFIGURABLE @@ -210,7 +210,6 @@ class NodeSerializer(TaxonomizableSerializerMixin, JSONAPISerializer): # list if it doesn't expose user data non_anonymized_fields = [ 'access_requests_enabled', - 'analytics_key', 'category', 'children', 'collection', @@ -274,7 +273,6 @@ class NodeSerializer(TaxonomizableSerializerMixin, JSONAPISerializer): tags = ValuesListField(attr_name='name', child=ser.CharField(), required=False) access_requests_enabled = ShowIfVersion(ser.BooleanField(read_only=False, required=False), min_version='2.0', max_version='2.8') node_license = NodeLicenseSerializer(required=False, source='license') - analytics_key = ShowIfAdminScopeOrAnonymous(ser.CharField(read_only=True, source='keenio_read_key')) template_from = ser.CharField( required=False, allow_blank=False, allow_null=False, help_text='Specify a node id for a node you would like to use as a template for the ' diff --git a/api_tests/nodes/serializers/test_serializers.py b/api_tests/nodes/serializers/test_serializers.py index 1d6f7a14da7..d139652796b 100644 --- a/api_tests/nodes/serializers/test_serializers.py +++ b/api_tests/nodes/serializers/test_serializers.py @@ -48,7 +48,6 @@ def test_node_serializer(self, user): assert attributes['registration'] == node.is_registration assert attributes['fork'] == node.is_fork assert attributes['collection'] == node.is_collection - assert attributes['analytics_key'] == node.keenio_read_key assert attributes['wiki_enabled'] == node.has_addon('wiki') # Relationships diff --git a/osf/management/commands/cumulative_plos_metrics.py b/osf/management/commands/cumulative_plos_metrics.py index 27a6aa8a47e..6c12f1dbb3e 100644 --- a/osf/management/commands/cumulative_plos_metrics.py +++ b/osf/management/commands/cumulative_plos_metrics.py @@ -1,22 +1,13 @@ import csv -import io -from datetime import datetime import logging import requests import tempfile -from django.core.management.base import BaseCommand -from keen import KeenClient from requests_oauthlib import OAuth2 -from addons.osfstorage.models import OsfStorageFile -from framework.celery_tasks import app as celery_app from osf.metrics import PreprintView, PreprintDownload -from osf.models import Guid, Node, OSFUser, Preprint, \ - Registration, TrashedFile from osf.utils.fields import ensure_str from website.settings import ( - KEEN, PLOS_METRICS_BASE_FOLDER, PLOS_METRICS_INITIAL_FILE_DOWNLOAD_URL, PLOS_METRICS_OSF_TOKEN, @@ -37,15 +28,6 @@ logger = logging.getLogger(__name__) -keen_client = None -keen_project = KEEN['public']['project_id'] -keen_key = KEEN['public']['read_key'] -if keen_project and keen_key: - keen_client = KeenClient( - project_id=keen_project, - read_key=keen_key - ) - def bearer_token_auth(token): token_dict = { 'token_type': 'Bearer', @@ -73,45 +55,6 @@ def parse_base_file(): assert csvr.fieldnames == COL_HEADERS, f'Unexpected headers: expected {COL_HEADERS}, got {csvr.fieldnames}' return csvr -def fetch_metric_data_by_guid(guid): - """return: tuple(, tuple(, )) - """ - g = Guid.load(guid) - if not g: - logger.error(f'Unable to find Guid {guid}') - return None, (0, 0) - obj = Guid.load(guid).referent - if isinstance(obj, Node): - return 'node', fetch_node_metric_data(obj) - elif isinstance(obj, Registration): - return 'registration', fetch_node_metric_data(obj) - elif isinstance(obj, Preprint): - return 'preprint', fetch_preprint_metric_data(obj) - elif isinstance(obj, OsfStorageFile): - return 'file', fetch_file_metric_data(obj) - elif isinstance(obj, TrashedFile): - return 'trashedfile', fetch_file_metric_data(obj) - elif isinstance(obj, OSFUser): - return 'user', (0, 0) - else: - logger.error(f'Unknown type for {guid}') - return 'Unknown', (0, 0) - -def fetch_node_metric_data(node): - """return: tuple(, ) - """ - views = keen_client.count( - f'pageviews-{node._id[0]}', - timeframe='this_20_years', - filters=[{ - 'property_name': 'node.id', - 'operator': 'eq', - 'property_value': node._id - }] - ) - downs = 0 # AbstractNodes do not download - return views, downs - def fetch_preprint_metric_data(preprint): """return: tuple(, ) @@ -126,37 +69,3 @@ def fetch_file_metric_data(file_): views = file_.get_view_count() downs = file_.get_download_count() return views, downs - -@celery_app.task(name='osf.management.commands.cumulative_plos_metrics') -def cumulative_plos_metrics(): - today = datetime.today() - file_name = f'{today.year}_{today.month}_{today.day}_PLOS_Metrics.csv' - file_path = f'{TEMP_FOLDER}{file_name}' - logger.info('Parsing initial file...') - init_data_iter = parse_base_file() - output = io.StringIO() - writer = csv.DictWriter(output, COL_HEADERS) - writer.writeheader() - logger.info('Gathering data...') - for r in init_data_iter: - r['type'], (r['views'], r['downloads']) = fetch_metric_data_by_guid(r['guid']) - writer.writerow(r) - params = { - 'kind': 'file', - 'name': file_name - } - logger.info('Writing data...') - with open(file_path, 'w') as writeFile: - writeFile.write(output.getvalue()) - logger.info('Uploading file...') - upload_metrics_file(file_path=file_path, params=params) - logger.info('Done.') - - -class Command(BaseCommand): - def handle(self, *args, **kwargs): - start_time = datetime.now() - logger.info(f'Script start time: {start_time}') - cumulative_plos_metrics() - end_time = datetime.now() - logger.info(f'Script end time: {end_time}') diff --git a/osf/models/node.py b/osf/models/node.py index 9598fd54d18..325538281b1 100644 --- a/osf/models/node.py +++ b/osf/models/node.py @@ -20,7 +20,6 @@ from django.dispatch import receiver from django.utils import timezone from django.utils.functional import cached_property -from keen import scoped_keys from psycopg2._psycopg import AsIs from typedmodels.models import TypedModel, TypedModelManager from guardian.models import ( @@ -57,7 +56,7 @@ translations as gv_translations, ) from osf.utils.datetime_aware_jsonfield import DateTimeAwareJSONField -from osf.utils.fields import NonNaiveDateTimeField, ensure_str +from osf.utils.fields import NonNaiveDateTimeField from osf.utils.requests import get_request_and_user_id, string_type_request_headers, get_current_request from osf.utils.workflows import CollectionSubmissionStates from osf.utils import sanitize @@ -479,8 +478,6 @@ def linked_nodes(self): identifiers = GenericRelation(Identifier, related_query_name='nodes') - keenio_read_key = models.CharField(max_length=1000, null=True, blank=True) - def __init__(self, *args, **kwargs): self._parent = kwargs.pop('parent', None) self._is_templated_clone = False @@ -1260,7 +1257,6 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat self.request_embargo_termination(auth.user) return False self.is_public = True - self.keenio_read_key = self.generate_keenio_read_key() elif permissions == 'private' and self.is_public: if self.is_registration and not self.is_pending_embargo and not force: raise NodeStateError('Public registrations must be withdrawn, not made private.') @@ -1268,7 +1264,6 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat self.check_privacy_change_viability(auth) self.is_public = False - self.keenio_read_key = '' self._remove_from_associated_collections(auth, force=force) else: return False @@ -1305,17 +1300,6 @@ def set_privacy(self, permissions, auth=None, log=True, save=True, meeting_creat project_signals.privacy_set_public.send(auth.user, node=self, meeting_creation=meeting_creation) return True - def generate_keenio_read_key(self): - encrypted_read_key = scoped_keys.encrypt(settings.KEEN['public']['master_key'], options={ - 'filters': [{ - 'property_name': 'node.id', - 'operator': 'eq', - 'property_value': str(self._id) - }], - 'allowed_operations': [READ] - }) - return ensure_str(encrypted_read_key) - @property def private_links_active(self): if self.is_spammy: diff --git a/osf_tests/test_node.py b/osf_tests/test_node.py index 4e88d1c2bf7..4fcd6e542cf 100644 --- a/osf_tests/test_node.py +++ b/osf_tests/test_node.py @@ -2254,11 +2254,9 @@ def test_set_privacy(self, node, auth): assert last_logged_before_method_call != node.last_logged node.save() assert bool(node.is_public) is True - assert node.keenio_read_key != '' node.set_privacy('private', auth=auth) node.save() assert bool(node.is_public) is False - assert node.keenio_read_key == '' assert node.logs.first().action == NodeLog.MADE_PRIVATE assert last_logged_before_method_call != node.last_logged diff --git a/scripts/tests/test_populate_popular_projects_and_registrations.py b/scripts/tests/test_populate_popular_projects_and_registrations.py index b1cf38c651d..98bc73d0459 100644 --- a/scripts/tests/test_populate_popular_projects_and_registrations.py +++ b/scripts/tests/test_populate_popular_projects_and_registrations.py @@ -8,88 +8,88 @@ from scripts import populate_popular_projects_and_registrations as script -class TestPopulateNewAndNoteworthy(OsfTestCase): - - def setUp(self): - super().setUp() - self.pop1 = ProjectFactory(is_public=True) - self.pop2 = ProjectFactory(is_public=True) - - self.popreg1 = RegistrationFactory(is_public=True) - self.popreg2 = RegistrationFactory(is_public=True) - - def tearDown(self): - super().tearDown() - - @mock.patch('website.project.utils.get_keen_activity') - def test_populate_popular_nodes_and_registrations(self, mock_client): - - # only for setup, not used - self.new_noteworthy_node = ProjectFactory() - self.new_noteworthy_node._id = NEW_AND_NOTEWORTHY_LINKS_NODE - self.new_noteworthy_node.save() - - self.popular_links_node = ProjectFactory() - self.popular_links_node._id = POPULAR_LINKS_NODE - self.popular_links_node.save() - - self.popular_links_registrations = ProjectFactory() - self.popular_links_registrations._id = POPULAR_LINKS_REGISTRATIONS - self.popular_links_registrations.save() - - popular_nodes = [self.pop1, self.pop2] - popular_registrations = [self.popreg1, self.popreg2] - - node_pageviews = [ - { - 'result': 5, - 'node.id': self.pop1._id - }, - { - 'result': 5, - 'node.id': self.pop2._id - }, - { - 'result': 5, - 'node.id': self.popreg1._id - }, - { - 'result': 5, - 'node.id': self.popreg2._id - } - ] - - node_visits = [ - { - 'result': 2, - 'node.id': self.pop1._id - }, - { - 'result': 2, - 'node.id': self.pop2._id - }, - { - 'result': 2, - 'node.id': self.popreg1._id - }, - { - 'result': 2, - 'node.id': self.popreg2._id - } - ] - - mock_client.return_value = {'node_pageviews': node_pageviews, 'node_visits': node_visits} - - assert len(self.popular_links_node.nodes) == 0 - assert len(self.popular_links_registrations.nodes) == 0 - - script.main(dry_run=False) - - self.popular_links_node.reload() - self.popular_links_registrations.reload() - - assert len(self.popular_links_node.nodes) == 2 - assert len(self.popular_links_registrations.nodes) == 2 - - assert popular_nodes == self.popular_links_node.nodes - assert popular_registrations == self.popular_links_registrations.nodes +# class TestPopulateNewAndNoteworthy(OsfTestCase): +# +# def setUp(self): +# super().setUp() +# self.pop1 = ProjectFactory(is_public=True) +# self.pop2 = ProjectFactory(is_public=True) +# +# self.popreg1 = RegistrationFactory(is_public=True) +# self.popreg2 = RegistrationFactory(is_public=True) +# +# def tearDown(self): +# super().tearDown() +# +# @mock.patch('website.project.utils.get_keen_activity') +# def test_populate_popular_nodes_and_registrations(self, mock_client): +# +# # only for setup, not used +# self.new_noteworthy_node = ProjectFactory() +# self.new_noteworthy_node._id = NEW_AND_NOTEWORTHY_LINKS_NODE +# self.new_noteworthy_node.save() +# +# self.popular_links_node = ProjectFactory() +# self.popular_links_node._id = POPULAR_LINKS_NODE +# self.popular_links_node.save() +# +# self.popular_links_registrations = ProjectFactory() +# self.popular_links_registrations._id = POPULAR_LINKS_REGISTRATIONS +# self.popular_links_registrations.save() +# +# popular_nodes = [self.pop1, self.pop2] +# popular_registrations = [self.popreg1, self.popreg2] +# +# node_pageviews = [ +# { +# 'result': 5, +# 'node.id': self.pop1._id +# }, +# { +# 'result': 5, +# 'node.id': self.pop2._id +# }, +# { +# 'result': 5, +# 'node.id': self.popreg1._id +# }, +# { +# 'result': 5, +# 'node.id': self.popreg2._id +# } +# ] +# +# node_visits = [ +# { +# 'result': 2, +# 'node.id': self.pop1._id +# }, +# { +# 'result': 2, +# 'node.id': self.pop2._id +# }, +# { +# 'result': 2, +# 'node.id': self.popreg1._id +# }, +# { +# 'result': 2, +# 'node.id': self.popreg2._id +# } +# ] +# +# mock_client.return_value = {'node_pageviews': node_pageviews, 'node_visits': node_visits} +# +# assert len(self.popular_links_node.nodes) == 0 +# assert len(self.popular_links_registrations.nodes) == 0 +# +# script.main(dry_run=False) +# +# self.popular_links_node.reload() +# self.popular_links_registrations.reload() +# +# assert len(self.popular_links_node.nodes) == 2 +# assert len(self.popular_links_registrations.nodes) == 2 +# +# assert popular_nodes == self.popular_links_node.nodes +# assert popular_registrations == self.popular_links_registrations.nodes diff --git a/website/project/utils.py b/website/project/utils.py index 173219d5558..e8eb0eaf526 100644 --- a/website/project/utils.py +++ b/website/project/utils.py @@ -1,14 +1,8 @@ """Various node-related utilities.""" -from string import ascii_lowercase, digits - from django.apps import apps from django.db.models import Q from website import settings - -from keen import KeenClient - - # Alias the project serializer def serialize_node(*args, **kwargs): @@ -28,47 +22,6 @@ def recent_public_registrations(n=10): ).get_roots().order_by('-registered_date')[:n] -def get_keen_activity(): - client = KeenClient( - project_id=settings.KEEN['public']['project_id'], - read_key=settings.KEEN['public']['read_key'], - ) - - node_pageviews = [] - node_visits = [] - for character in list(digits + ascii_lowercase): - partial_node_pageviews = client.count( - event_collection=f'pageviews-{character}', - timeframe='this_7_days', - group_by='node.id', - filters=[ - { - 'property_name': 'node.id', - 'operator': 'exists', - 'property_value': True - } - ] - ) - node_pageviews += partial_node_pageviews - - partial_node_visits = client.count_unique( - event_collection=f'pageviews-{character}', - target_property='anon.id', - timeframe='this_7_days', - group_by='node.id', - filters=[ - { - 'property_name': 'node.id', - 'operator': 'exists', - 'property_value': True - } - ] - ) - node_visits += partial_node_visits - - return {'node_pageviews': node_pageviews, 'node_visits': node_visits} - - def activity(): """Generate analytics for most popular public projects and registrations. Called by `scripts/update_populate_projects_and_registrations` @@ -76,33 +29,8 @@ def activity(): Node = apps.get_model('osf.AbstractNode') popular_public_projects = [] popular_public_registrations = [] - max_projects_to_display = settings.MAX_POPULAR_PROJECTS - - if settings.KEEN['public']['read_key']: - keen_activity = get_keen_activity() - node_visits = keen_activity['node_visits'] - - node_data = [{'node': x['node.id'], 'views': x['result']} for x in node_visits] - node_data.sort(key=lambda datum: datum['views'], reverse=True) - - node_data = [node_dict['node'] for node_dict in node_data] - - for nid in node_data: - node = Node.load(nid) - if node is None: - continue - if node.is_public and not node.is_registration and not node.is_deleted: - if len(popular_public_projects) < max_projects_to_display: - popular_public_projects.append(node) - elif node.is_public and node.is_registration and not node.is_deleted and not node.is_retracted: - if len(popular_public_registrations) < max_projects_to_display: - popular_public_registrations.append(node) - if len(popular_public_projects) >= max_projects_to_display and len(popular_public_registrations) >= max_projects_to_display: - break - # New and Noteworthy projects are updated manually new_and_noteworthy_projects = list(Node.objects.get(guids___id=settings.NEW_AND_NOTEWORTHY_LINKS_NODE, guids___id__isnull=False).nodes_pointer) - return { 'new_and_noteworthy_projects': new_and_noteworthy_projects, 'recent_public_registrations': recent_public_registrations(), @@ -110,7 +38,6 @@ def activity(): 'popular_public_registrations': popular_public_registrations } - # Credit to https://gist.github.com/cizixs/be41bbede49a772791c08491801c396f def sizeof_fmt(num, suffix='B'): for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']: diff --git a/website/routes.py b/website/routes.py index 5ff15e053a1..967df684d79 100644 --- a/website/routes.py +++ b/website/routes.py @@ -150,16 +150,6 @@ def get_globals(): 'profile_url': cas.get_profile_url(), 'enable_institutions': settings.ENABLE_INSTITUTIONS, 'page_route_name': request.url_rule.endpoint.replace('__', '.'), - 'keen': { - 'public': { - 'project_id': settings.KEEN['public']['project_id'], - 'write_key': settings.KEEN['public']['write_key'], - }, - 'private': { - 'project_id': settings.KEEN['private']['project_id'], - 'write_key': settings.KEEN['private']['write_key'], - }, - }, 'institutional_landing_flag': flag_is_active(request, features.INSTITUTIONAL_LANDING_FLAG), 'maintenance': maintenance.get_maintenance(), 'recaptcha_site_key': settings.RECAPTCHA_SITE_KEY, diff --git a/website/settings/defaults.py b/website/settings/defaults.py index 1bb36e6ce3e..560c68df42e 100644 --- a/website/settings/defaults.py +++ b/website/settings/defaults.py @@ -444,7 +444,7 @@ class CeleryConfig: 'osf.management.commands.sync_datacite_doi_metadata', 'osf.management.commands.update_institution_project_counts', 'osf.management.commands.populate_branched_from', - 'osf.management.commands.cumulative_plos_metrics', + # 'osf.management.commands.cumulative_plos_metrics', 'osf.management.commands.spam_metrics', 'osf.management.commands.daily_reporters_go', 'osf.management.commands.monthly_reporters_go', @@ -549,7 +549,7 @@ class CeleryConfig: 'osf.management.commands.delete_legacy_quickfiles_nodes', 'osf.management.commands.fix_quickfiles_waterbutler_logs', 'osf.management.commands.sync_doi_metadata', - 'osf.management.commands.cumulative_plos_metrics', + # 'osf.management.commands.cumulative_plos_metrics', 'api.providers.tasks', 'osf.management.commands.daily_reporters_go', 'osf.management.commands.monthly_reporters_go', diff --git a/website/templates/base.mako b/website/templates/base.mako index d168bc17af3..dd74823dbd8 100644 --- a/website/templates/base.mako +++ b/website/templates/base.mako @@ -271,24 +271,6 @@ }); - % if keen['public']['project_id']: - - % endif - - ${self.javascript_bottom()} From 873a011591dfd18aad13def3f00c7381a1e01c7a Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 21 Feb 2025 15:17:24 +0200 Subject: [PATCH 02/19] add migration --- .../0028_remove_abstractnode_keenio_read_key.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 osf/migrations/0028_remove_abstractnode_keenio_read_key.py diff --git a/osf/migrations/0028_remove_abstractnode_keenio_read_key.py b/osf/migrations/0028_remove_abstractnode_keenio_read_key.py new file mode 100644 index 00000000000..55f472b1af9 --- /dev/null +++ b/osf/migrations/0028_remove_abstractnode_keenio_read_key.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.15 on 2025-02-21 13:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('osf', '0027_alter_guidversionsthrough_object_id'), + ] + + operations = [ + migrations.RemoveField( + model_name='abstractnode', + name='keenio_read_key', + ), + ] From f20d0e7c26b965545555c30e71befb6df3f49ae1 Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 21 Feb 2025 20:30:53 +0200 Subject: [PATCH 03/19] remove legacy keen from metrics .js (maybe another keen logic is also needed to be removed in the files) --- admin/static/js/metrics/metrics.es6.js | 54 ++++++++++++------------ admin/static/js/pages/metrics-page.js | 6 +-- admin/templates/metrics/osf_metrics.html | 2 +- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/admin/static/js/metrics/metrics.es6.js b/admin/static/js/metrics/metrics.es6.js index 42da8ffd8ac..daa29cff464 100644 --- a/admin/static/js/metrics/metrics.es6.js +++ b/admin/static/js/metrics/metrics.es6.js @@ -1086,35 +1086,35 @@ function renderPreprintMetrics(timeframe) { var DownloadMetrics = function() { // ********** legacy keen ********** - var totalDownloadsQuery = new keenAnalysis.Query("count", { - eventCollection: "file_stats", - timeframe: 'previous_1_days', - filters: [{ - property_name: 'action.type', - operator: 'eq', - property_value: 'download_file', - timezone: "UTC" - }] - }); - renderKeenMetric("#number-of-downloads", "metric", totalDownloadsQuery, - defaultHeight, defaultColor, publicClient); + // var totalDownloadsQuery = new keenAnalysis.Query("count", { + // eventCollection: "file_stats", + // timeframe: 'previous_1_days', + // filters: [{ + // property_name: 'action.type', + // operator: 'eq', + // property_value: 'download_file', + // timezone: "UTC" + // }] + // }); + // renderKeenMetric("#number-of-downloads", "metric", totalDownloadsQuery, + // defaultHeight, defaultColor, publicClient); // ********** legacy keen ********** - var uniqueDownloadsQuery = new keenAnalysis.Query("count_unique", { - eventCollection: "file_stats", - timeframe: 'previous_1_days', - target_property: 'file.resource', - filters: [{ - property_name: 'action.type', - operator: 'eq', - property_value: 'download_file', - timezone: "UTC" - }] - }); - renderKeenMetric("#number-of-unique-downloads", "metric", uniqueDownloadsQuery, - defaultHeight, defaultColor, publicClient); - - renderDownloadMetrics(); + // var uniqueDownloadsQuery = new keenAnalysis.Query("count_unique", { + // eventCollection: "file_stats", + // timeframe: 'previous_1_days', + // target_property: 'file.resource', + // filters: [{ + // property_name: 'action.type', + // operator: 'eq', + // property_value: 'download_file', + // timezone: "UTC" + // }] + // }); + // renderKeenMetric("#number-of-unique-downloads", "metric", uniqueDownloadsQuery, + // defaultHeight, defaultColor, publicClient); + + // renderDownloadMetrics(); }; function renderDownloadMetrics(timeframe) { diff --git a/admin/static/js/pages/metrics-page.js b/admin/static/js/pages/metrics-page.js index dedd46e0570..8f2b89e08d4 100644 --- a/admin/static/js/pages/metrics-page.js +++ b/admin/static/js/pages/metrics-page.js @@ -27,9 +27,9 @@ keenAnalysis.ready(function() { $('#preprints-tab')[0].onclick = function() { Metrics.PreprintMetrics(); }; - $('#downloads-tab')[0].onclick = function() { - Metrics.DownloadMetrics(); - }; + // $('#downloads-tab')[0].onclick = function() { + // Metrics.DownloadMetrics(); + // }; $('#preprints-range')[0].onclick = function() { Metrics.RenderPreprintMetrics({ start: $('#start-date')[0].value, diff --git a/admin/templates/metrics/osf_metrics.html b/admin/templates/metrics/osf_metrics.html index f01f0513a7e..30dce60e3a2 100644 --- a/admin/templates/metrics/osf_metrics.html +++ b/admin/templates/metrics/osf_metrics.html @@ -32,7 +32,7 @@

OSF Metrics

- + From b6cd8559a6ed5ae3a39b6a29e0d44bdcdd6533fb Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 21 Feb 2025 20:41:04 +0200 Subject: [PATCH 04/19] remove dashboard keen (it is not used in any views) --- admin/static/css/keen-dashboards.css | 120 ----- admin/static/js/sales_analytics/dashboard.js | 409 ------------------ .../templates/sales_analytics/dashboard.html | 223 ---------- 3 files changed, 752 deletions(-) delete mode 100755 admin/static/css/keen-dashboards.css delete mode 100644 admin/static/js/sales_analytics/dashboard.js delete mode 100644 admin/templates/sales_analytics/dashboard.html diff --git a/admin/static/css/keen-dashboards.css b/admin/static/css/keen-dashboards.css deleted file mode 100755 index b8e7a507681..00000000000 --- a/admin/static/css/keen-dashboards.css +++ /dev/null @@ -1,120 +0,0 @@ - -/* - * Full-page application style - */ - -body.application, -.keen-dashboard { - background: #f2f2f2; - font-family: 'Gotham Rounded SSm A', 'Gotham Rounded SSm B', 'Helvetica Neue', Helvetica, Arial, sans-serif; - padding: 60px 20px 0; -} - -body.application > .container-fluid, -.keen-dashboard > .container-fluid { - margin: 0 0 32px; - margin: 0 0 2rem; - padding-left: 0; - padding-right: 0; -} - -body.application div[class^="col-"], -.keen-dashboard div[class^="col-"] { - padding-left: 5px; - padding-right: 5px; -} - -body.application div[class^="col-"] div[class^="col-"], -.keen-dashboard div[class^="col-"] div[class^="col-"] { - padding-left: 15px; - padding-right: 15px; -} - -body.application hr, -.keen-dashboard hr { - border-color: #d7d7d7; - margin: 10px 0; -} - -body.application .navbar-inverse, -.keen-dashboard .navbar-inverse { - background-color: #3d4a57; - border-color: #333; -} - -body.application .navbar-inverse .navbar-nav > li > a, -body.application .navbar .navbar-brand, -.keen-dashboard .navbar-inverse .navbar-nav > li > a, -.keen-dashboard .navbar .navbar-brand { - color: #fbfbfb; - text-decoration: none; -} - -body.application .main-nav > li > a:hover, -.keen-dashboard .main-nav > li > a:hover { - border-bottom: 2px solid transparent; - -webkit-transition: border 300ms ease; - -o-transition: border 300ms ease; - transition: border 300ms ease; - border-bottom-color: white; -} - -body.application .return-link, -body.application .return-link:focus, -body.application .return-link:hover, -.keen-dashboard .return-link, -.keen-dashboard .return-link:focus, -.keen-dashboard .return-link:hover { - text-decoration: none; -} - - -.chart-wrapper { - background: #fff; - border: 1px solid #e2e2e2; - border-radius: 3px; - margin-bottom: 10px; -} -.chart-wrapper .chart-title { - border-bottom: 1px solid #d7d7d7; - color: #666; - font-size: 14px; - font-weight: 200; - padding: 7px 10px 4px; -} - -.chart-wrapper .chart-stage { - overflow: hidden; - padding: 5px 10px; - position: relative; -} - -.chart-wrapper .chart-notes { - background: #fbfbfb; - border-top: 1px solid #e2e2e2; - color: #808080; - font-size: 12px; - padding: 8px 10px 5px; -} - -.keen-dataviz-table-dataset td{ - min-width: 60px !important; -} - -#dropdownMenuButton { - margin-top: 20px; - margin-right: 20px; -} - -.institution-tables thead { - display: none; -} - -.hr-menu { - background-color: lightgray; - height: 1px; -} - -#reload-node-logs { - margin-left: 20px; -} diff --git a/admin/static/js/sales_analytics/dashboard.js b/admin/static/js/sales_analytics/dashboard.js deleted file mode 100644 index 19eb217c27d..00000000000 --- a/admin/static/js/sales_analytics/dashboard.js +++ /dev/null @@ -1,409 +0,0 @@ -require('bootstrap'); -require('jquery'); -require('c3/c3.css'); - -var c3 = require('c3/c3.js'); -var keen = require('keen-js'); -var ss = require('simple-statistics'); - -var SalesAnalytics = function() { - // Metrics and visualization for the analytics dashboard. - var self = this; - - self.keenClient = new keen({ - projectId: keenProjectId, - readKey : keenReadKey - }); - - self.keenFilters = { - nullUserFilter: { - property_name: 'user.id', - operator: 'ne', - property_value: null - }, - inactiveUserFilter: { - property_name: 'user.id', - operator: 'ne', - property_value: '' - } - }; - self.getAverageUserSessionLength = function () { - var query = new keen.Query('select_unique', { - event_collection: 'pageviews', - timeframe: 'previous_7_days', - target_property: 'keen.timestamp', - group_by: ['user.id', 'sessionId'], - filters: [self.keenFilters.nullUserFilter] - }); - - var chart = self.prepareChart('keen-chart-average-session-user'); - - self.keenClient.run(query, function(error, response) { - if (error) { - document.getElementById('keen-chart-average-session-user').innerHTML = 'Keen Query Failure'; - console.log(error); - } - else { - var dataSet = self.extractDataSet(response); - var result = ss.mean(dataSet); - self.drawChart(chart, 'metric', 'Minutes', result/1000/60); - } - }); - }; - - self.getAverageMAUSessionLength = function() { - var query = new keen.Query('select_unique', { - event_collection: 'pageviews', - timeframe: 'previous_7_days', - target_property: 'keen.timestamp', - group_by: ['user.id', 'sessionId'], - filters: [self.keenFilters.nullUserFilter, self.keenFilters.inactiveUserFilter] - }); - - var chart = self.prepareChart('keen-chart-average-session-mau'); - - self.keenClient.run(query, function(error, response) { - if (error) { - document.getElementById('keen-chart-average-session-mau').innerHTML = 'Keen Query Failure.'; - console.log(error); - } - else { - var dataSet = self.extractDataSet(response); - var result = ss.mean(dataSet); - self.drawChart(chart, 'metric', 'Minutes', result/1000/60); - } - }); - }; - - self.getAverageUserSessionHistory = function(init, numberOfWeeks, weekEnd, weekStart, weeklyResult) { - if (init === true) { - var date = new Date(); - date.setHours(0, 0, 0, 0); - date.setDate(date.getDate() - date.getDay()); - weekEnd = new Date(date); - weekStart = new Date(date.setDate(date.getDate() - 7)); - weeklyResult = []; - self.getAverageUserSessionHistory(false, numberOfWeeks, weekEnd, weekStart, weeklyResult); - return; - } - - if (numberOfWeeks === 0) { - var chart = self.prepareChart('keen-chart-average-session-history'); - chart.attributes({title: 'Average User/MAU Session Length History of Past 12 Weeks', width: '100%', height: 450}); - chart.adapter({chartType: 'columnchart'}); - chart.chartOptions({ - hAxis: {title: 'Week'}, - vAxis: {title: 'Minutes'} - }); - chart.parseRawData({result: weeklyResult}).render(); - return; - } - - document.getElementById('keen-chart-average-session-history').innerHTML = 'loading ... : ' + (12 - numberOfWeeks) + ' / 12'; - var queryUser = new keen.Query('select_unique', { - event_collection: 'pageviews', - timeframe: { - start: weekStart.toISOString(), - end: weekEnd.toISOString() - }, - target_property: 'keen.timestamp', - group_by: ['user.id', 'sessionId'], - filters: [self.keenFilters.nullUserFilter] - }); - var queryMAU = new keen.Query('select_unique', { - event_collection: 'pageviews', - timeframe: { - start: weekStart.toISOString(), - end: weekEnd.toISOString() - }, - target_property: 'keen.timestamp', - group_by: ['user.id', 'sessionId'], - filters: [self.keenFilters.nullUserFilter, self.keenFilters.inactiveUserFilter] - }); - - self.keenClient.run([queryUser, queryMAU], function (error, response) { - var resultUser; - var resultMAU; - if (error) { - document.getElementById('keen-chart-average-session-history').innerHTML = 'failure ... : ' + (12 - numberOfWeeks) + ' / 12'; - console.log(error); - resultUser = resultMAU = -1; - } - else { - var dataSetUser = self.extractDataSet(response[0]); - var dataSetMAU = self.extractDataSet(response[1]); - resultUser = ss.mean(dataSetUser); - resultMAU = ss.mean(dataSetMAU); - } - var item = { - timeframe: { - start: weekStart.toISOString(), - end: weekEnd.toISOString() - }, - value: [ - { category: 'User', result: resultUser/1000/60 }, - { category: 'MAU', result: resultMAU/1000/60 } - ] - }; - weeklyResult.push(item); - - weekEnd = new Date(weekStart); - weekStart.setDate(weekEnd.getDate() - 7); - numberOfWeeks--; - self.getAverageUserSessionHistory(false, numberOfWeeks, weekEnd, weekStart, weeklyResult); - }); - }; - - self.getOSFProductUsage = function() { - var query = new Keen.Query('select_unique', { - event_collection: 'pageviews', - timeframe: 'previous_1_months', - target_property: 'parsedPageUrl.path', - group_by: ['user.id', 'parsedPageUrl.domain'], - filters: [self.keenFilters.nullUserFilter, self.keenFilters.inactiveUserFilter] - }); - - var chartMoreThanTwo = self.prepareChart('keen-chart-osf-product-usage-mt2'); - var chartMeetings = self.prepareChart('keen-chart-osf-product-usage-mee'); - var chartInstitutions = self.prepareChart('keen-chart-osf-product-usage-ins'); - - var request = self.keenClient.run(query, function(error, response) { - if (error) { - document.getElementById('keen-chart-osf-product-usage-mt2').innerHTML = 'Keen Query Failure'; - } - else { - var userProductMap = self.numberOfUsers(response); - self.drawChart(chartMoreThanTwo, 'piechart', '', [ - {products: 'OSF Only', count: userProductMap.osf.length - userProductMap.moreThanTwo.length}, - {products: '2+ Products', count: userProductMap.moreThanTwo.length} - ]); - self.drawChart(chartMeetings, 'piechart', '', [ - {products: 'No Meetings', count: userProductMap.osf.length - userProductMap.meetings.length}, - {products: 'Meetings', count: userProductMap.meetings.length} - ]); - self.drawChart(chartInstitutions, 'piechart', '', [ - {products: 'No Institutions', count: userProductMap.osf.length - userProductMap.institutions.length}, - {products: 'Institutions', count: userProductMap.institutions.length} - ]); - } - }); - }; - self.getUserCount = function(userCount) { - // User count for each peroduct (osf, osf4m, institution) - var chart = c3.generate({ - bindto: '#db-chart-user-count', - data: { - columns: [['Count'].concat(userCount.count)], - type: 'bar', - colors: { - Count: '#ff5a5f', - } - }, - axis: { - x: { - type: 'category', - categories: userCount.tags, - }, - rotated: true - }, - bar: { - width: { - ratio: 0.5 // this makes bar width 50% of length between ticks - } - } - }); - }; - - self.getUserPercentage = function(userCount) { - var chart = c3.generate({ - bindto: '#db-chart-user-percent', - data: { - columns: [['Percentage'].concat(userCount.percent)], - type: 'bar', - colors: { - Count: '#ff8083', - } - }, - axis: { - x: { - type: 'category', - categories: userCount.tags, - }, - rotated: true - }, - bar: { - width: { - ratio: 0.5 // this makes bar width 50% of length between ticks - } - } - }); - }; - - self.getMultiProductCountYearly = function(multiProductMetricsYearly) { - // Number of users that use 2+ products - var chart = self.drawMetric('db-chart-multi-product-yearly', - multiProductMetricsYearly.multi_product_count, - '#e57fc2', - 'Users'); - }; - - self.getMultiProductCountMonthly = function(multiProductMetricsMonthly) { - var chart = self.drawMetric('db-chart-multi-product-monthly', - multiProductMetricsMonthly.multi_product_count, - '#e57fc2', - 'Users'); - }; - - self.getCrossProductCountYearly = function(multiProductMetricsYearly) { - // Number of users that use a product different from their entry points. - var chart = self.drawMetric('db-chart-cross-product-yearly', - multiProductMetricsYearly.cross_product_count, - '#6ab975', - 'Users'); - }; - - self.getCrossProductCountMonthly = function(multiProductMetricsMonthly) { - var chart = self.drawMetric('db-chart-cross-product-monthly', - multiProductMetricsMonthly.cross_product_count, - '#6ab975', - 'Users'); - }; - - self.getMultiActionCountYearly = function(multiProductMetricsYearly) { - // Number of users that have more than one type of action. - var chart = self.drawMetric('db-chart-multi-action-yearly', - multiProductMetricsYearly.multi_action_count, - '#4C72B7', - 'Users'); - }; - - self.getMultiActionCountMonthly = function(multiProductMetricsMonthly) { - var chart = self.drawMetric('db-chart-multi-action-monthly', - multiProductMetricsMonthly.multi_action_count, - '#4C72B7', - 'Users'); - }; - - self.getRepeatActionCountMonthly = function(repeatActionUserMonthly) { - var chart = self.drawMetric('db-chart-repeat-action-monthly', - repeatActionUserMonthly.repeat_action_count, - '#b75c4c', - 'Users'); - }; - - self.getTotalUserCount = function(userCount) { - var chart = self.drawMetric('db-chart-total-user', - userCount.total, - '#005c66', - 'Users'); - }; - - self.prepareChart = function(elementId) { - var chart = new keen.Dataviz(); - return chart.el(document.getElementById(elementId)).prepare(); - }; - - self.drawChart = function(chart, type, title, result, color) { - chart.attributes({title: title, width: '100%'}); - chart.adapter({chartType: type}); - chart.parseRawData({result: result}); - chart.render(); - }; - - self.drawMetric = function(elementId, result, color, title) { - var chart = new keen.Dataviz() - .el(document.getElementById(elementId)) - .parseRawData({ result: result }) - .chartType('metric') - .colors([color]) - .title(title) - .render(); - }; - - self.init = function() { - console.log('init'); - keen.ready(self.run()); - }; - - self.run = function() { - console.log('run'); - self.getOSFProductUsage(); - self.getAverageUserSessionLength(); - self.getAverageMAUSessionLength(); - self.getAverageUserSessionHistory(true, 12, null, null, null); - self.getUserCount(userCount); - self.getUserPercentage(userCount); - self.getMultiProductCountYearly(multiProductMetricsYearly); - self.getMultiProductCountMonthly(multiProductMetricsMonthly); - self.getCrossProductCountYearly(multiProductMetricsYearly); - self.getCrossProductCountMonthly(multiProductMetricsMonthly); - self.getMultiActionCountYearly(multiProductMetricsYearly); - self.getMultiActionCountMonthly(multiProductMetricsMonthly); - self.getRepeatActionCountMonthly(repeatActionUserMonthly); - self.getTotalUserCount(userCount); - }; - - self.extractDataSet = function(keenResult) { - if (!keenResult) { - return 0; - } - - var beginTime; - var endTime; - var deltaSet = []; - - for (var i in keenResult.result) { - var session = keenResult.result[i]; - if (session.hasOwnProperty('result')) { - if (session.result.length === 1) { - // TODO: take care of the situation where there is only one 'keen.timestamp' - continue; - } - beginTime = Date.parse(session.result[0]); - endTime = Date.parse(session.result[session.result.length-1]); - deltaSet.push(endTime - beginTime); - } - } - return deltaSet; - }; - - self.numberOfUsers = function(keenResult, filters) { - var userProductMap = { - 'osf': [], - 'meetings': [], - 'institutions': [], - 'moreThanTwo': [] - }; - for (var i in keenResult.result) { - var session = keenResult.result[i]; - if (session.hasOwnProperty('result') && session.hasOwnProperty('user.id')) { - if (session.hasOwnProperty('parsedPageUrl.domain') && session['parsedPageUrl.domain'] === 'staging.osf.io') { - userProductMap.osf.push(session['user.id']); - var paths = session.result; - var numberOfProducts = 0; - var meetings, institutions; - meetings = institutions = false; - for (var j in paths) { - if (meetings === false && paths[j].startsWith('/meetings/')) { - userProductMap.meetings.push(session['user.id']); - meetings = true; - numberOfProducts ++; - } - else if (institutions === false && paths[j].startsWith('/institutions/')) { - userProductMap.institutions.push(session['user.id']); - meetings = true; - numberOfProducts ++; - } - } - if (numberOfProducts > 0) { - userProductMap.moreThanTwo.push(session['user.id']); - } - } - } - } - return userProductMap; - }; -}; - -var salesAnalytics = new SalesAnalytics(); -salesAnalytics.init(); diff --git a/admin/templates/sales_analytics/dashboard.html b/admin/templates/sales_analytics/dashboard.html deleted file mode 100644 index f3218b47a15..00000000000 --- a/admin/templates/sales_analytics/dashboard.html +++ /dev/null @@ -1,223 +0,0 @@ -{% extends 'base_analytics.html' %} -{% load static %} -{% load filters %} - -{% block top_analytics %} - -{% endblock top_analytics %} - - -{% block title_analytics %} -

Dashboard

-{% endblock title_analytics %} - -{% block content_analytics %} - - - Dashboard - - - - - -
- -
-
-
-
-
-
- Average User/MAU Session Length History of past 12 weeks -
-
-
-
...
-
-
-
- Notes about this chart -
-
-
-
-
-
-
-
- User Count by Product -
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- User count/percentage for each peroduct (osf, osf4m, institution) -
-
-
-
-
-
-
-
-
-
- OSF Products Users View in the Past Month -
-
-
...
-
...
-
-
- Notes about this chart -
-
-
-
-
-
- OSF Products Users View in the Past Month -
-
-
...
-
...
-
-
- Notes about this chart -
-
-
- - -
-
-
- Average User Session Length of Previous 7 days -
-
-
-
-
-
-
- Average MAU Session Length of Previous 7 days -
-
-
...
-
-
-
-
-
-
- Multi-product User Count (Year) -
-
-
-
-
-
-
- Multi-product User Count (Month) -
-
-
-
-
- Number of users that use 2+ products -
-
-
-
-
-
- Cross-product User Count (Year) -
-
-
-
-
-
-
- Cross-product User Count (Month) -
-
-
-
-
- Number of users that use a product other than their entry points. -
-
-
-
-
-
- Multi-action User Count (Year) -
-
-
-
-
-
-
- Multi-action User Count (Month) -
-
-
-
-
- Number of users that have more than one type of actions. -
-
-
-
-
-
- Repetitive actions User Count (Month) -
-
-
-
-
-
-
- Total User Count -
-
-
-
-
- Total number of Users -
-
-
-
-
-
- - -{% endblock content_analytics %} - -{% block bottom_js %} - -{% endblock %} From 5c2255e8bd2e155a8939959fd19906009535aaa7 Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 28 Feb 2025 12:09:16 +0200 Subject: [PATCH 05/19] ENG-5751 code updates --- admin/templates/metrics/osf_metrics.html | 7 ------- admin/webpack.admin.config.js | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/admin/templates/metrics/osf_metrics.html b/admin/templates/metrics/osf_metrics.html index 30dce60e3a2..99f920a9d9a 100644 --- a/admin/templates/metrics/osf_metrics.html +++ b/admin/templates/metrics/osf_metrics.html @@ -7,15 +7,8 @@ {% endblock title %} {% block top_includes %} - diff --git a/admin/webpack.admin.config.js b/admin/webpack.admin.config.js index e9987f2ed9d..fd1a8eb1e46 100644 --- a/admin/webpack.admin.config.js +++ b/admin/webpack.admin.config.js @@ -32,7 +32,7 @@ var config = Object.assign({}, common, { entry: { 'admin-base-page': staticAdminPath('js/pages/base-page.js'), 'admin-registration-edit-page': staticAdminPath('js/pages/admin-registration-edit-page.js'), - 'dashboard': staticAdminPath('js/sales_analytics/dashboard.js'), + // 'dashboard': staticAdminPath('js/sales_analytics/dashboard.js'), 'metrics-page': staticAdminPath('js/pages/metrics-page.js'), 'banners': staticAdminPath('js/banners/banners.js'), 'brands': staticAdminPath('js/brands/brands.js'), From f081bd2747af618673918c62dedbb59ce9874083 Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 28 Feb 2025 15:11:24 +0200 Subject: [PATCH 06/19] ENG-5751 remove keen dependency from poetry --- poetry.lock | 61 +++----------------------------------------------- pyproject.toml | 1 - 2 files changed, 3 insertions(+), 59 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8f0067d8d41..3c54b000ffa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -1249,6 +1249,7 @@ python-versions = "*" files = [ {file = "django-sendgrid-v5-1.2.3.tar.gz", hash = "sha256:3887aafbb10d5b808efc2c1031dcd96fd357d542eb5affe38fef07cc0f3cfae9"}, {file = "django_sendgrid_v5-1.2.3-py2.py3-none-any.whl", hash = "sha256:2d2fa8a085d21c95e5f97fc60b61f199ccc57a27df8da90cd3f29a5702346dc6"}, + {file = "django_sendgrid_v5-1.2.3-py3-none-any.whl", hash = "sha256:f6a44ee37c1c3cc7d683a43c55ead530417be1849a8a41bde02b158009559d9d"}, ] [package.dependencies] @@ -2449,21 +2450,6 @@ files = [ [package.dependencies] referencing = ">=0.31.0" -[[package]] -name = "keen" -version = "0.7.0" -description = "Python Client for Keen IO" -optional = false -python-versions = "*" -files = [ - {file = "keen-0.7.0.tar.gz", hash = "sha256:141fad22abd52dbe9e84a21866a7affcbc8b46f04885a5598618c5992bd6667c"}, -] - -[package.dependencies] -pycryptodome = ">=3.4" -requests = ">=2.5,<3.0" -six = ">=1.10,<2.0" - [[package]] name = "kombu" version = "5.3.5" @@ -3467,47 +3453,6 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -[[package]] -name = "pycryptodome" -version = "3.20.0" -description = "Cryptographic library for Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, - {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, -] - [[package]] name = "pydevd" version = "3.0.3" @@ -5070,4 +5015,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "1de9354e338d27f87b817d801505ffbc9bc5e6a9d7cd80e06480eace40a1da11" +content-hash = "2a738097299109ceff7103b399d643fa4d01a74b6a41499ddc798a11150d98a8" diff --git a/pyproject.toml b/pyproject.toml index 051291fc333..39e1e82f493 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,6 @@ django-webpack-loader = {git = "https://github.com/CenterForOpenScience/django-w django-sendgrid-v5 = "1.2.3" # metadata says python 3.10 not supported, but tests pass # Analytics requirements -keen = "0.7.0" geoip2 = "4.7.0" # OSF models django-typed-models = "0.14.0" From 4df563c3acd662df94ddcb63caf588b58db631fe Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 28 Feb 2025 15:50:06 +0200 Subject: [PATCH 07/19] ENG-5751 code updates --- admin/templates/metrics/osf_metrics.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/admin/templates/metrics/osf_metrics.html b/admin/templates/metrics/osf_metrics.html index 99f920a9d9a..023d6f7846e 100644 --- a/admin/templates/metrics/osf_metrics.html +++ b/admin/templates/metrics/osf_metrics.html @@ -9,6 +9,12 @@ {% block top_includes %} From 4cf4dc7c7421a1e401b21431cb88123b396b7695 Mon Sep 17 00:00:00 2001 From: mkovalua Date: Fri, 28 Feb 2025 17:00:31 +0200 Subject: [PATCH 08/19] code updates --- admin/templates/metrics/osf_metrics.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/templates/metrics/osf_metrics.html b/admin/templates/metrics/osf_metrics.html index 023d6f7846e..14bfcf8f1c7 100644 --- a/admin/templates/metrics/osf_metrics.html +++ b/admin/templates/metrics/osf_metrics.html @@ -26,7 +26,7 @@

OSF Metrics