Skip to content

Commit

Permalink
add institutional dashboard summary.
Browse files Browse the repository at this point in the history
  • Loading branch information
John Tordoff committed Aug 23, 2024
1 parent 3920a29 commit 176253a
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 1 deletion.
4 changes: 3 additions & 1 deletion api/institutions/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ class MetricsCSVRenderer(CSVRenderer):
CSVRenderer with updated render method to export `data` dictionary of API Response to CSV
"""

def render(self, data, media_type=None, renderer_context={}, writer_opts=None):
def render(self, data, media_type=None, renderer_context=None, writer_opts=None):
"""
Overwrites CSVRenderer.render() to create a CSV with the data dictionary
instead of the entire API response. This is necessary for results to be
separated into different rows.
"""
if not renderer_context:
renderer_context = {}
data = data.get('data')
return super().render(data, media_type=media_type, renderer_context=renderer_context, writer_opts=writer_opts)

Expand Down
1 change: 1 addition & 0 deletions api/metrics/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def get(self, request, *args, **kwargs):
VIEWABLE_REPORTS = {
'download_count': reports.DownloadCountReport,
'institution_summary': reports.InstitutionSummaryReport,
'institution_dashboard_summary': reports.InstitutionDashboardSummaryReport,
'node_summary': reports.NodeSummaryReport,
'osfstorage_file_count': reports.OsfstorageFileCountReport,
'preprint_summary': reports.PreprintSummaryReport,
Expand Down
2 changes: 2 additions & 0 deletions osf/metrics/reporters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .storage_addon_usage import StorageAddonUsageReporter
from .download_count import DownloadCountReporter
from .institution_summary import InstitutionSummaryReporter
from .institution_dashboard_summary import InstitutionDashboardSummaryReport
from .new_user_domain import NewUserDomainReporter
from .node_count import NodeCountReporter
from .osfstorage_file_count import OsfstorageFileCountReporter
Expand All @@ -14,6 +15,7 @@
# ActiveUserReporter,
DownloadCountReporter,
InstitutionSummaryReporter,
InstitutionDashboardSummaryReport,
NewUserDomainReporter,
NodeCountReporter,
OsfstorageFileCountReporter,
Expand Down
77 changes: 77 additions & 0 deletions osf/metrics/reporters/institution_dashboard_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import logging

from django.db.models import Q

from osf.metrics.reports import (
InstitutionDashboardSummaryReport,
RunningTotal,
NodeRunningTotals,
RegistrationRunningTotals,
FileRunningTotals,
DataRunningTotals
)
from osf.models import Institution
from ._base import DailyReporter


logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)


class InstitutionDashboardSummaryReporter(DailyReporter):
def report(self, date):
institutions = Institution.objects.all()
reports = []

daily_query = Q(created__date=date)
public_query = Q(is_public=True)
private_query = Q(is_public=False)

embargo_v2_query = Q(root__embargo__end_date__date__gt=date)

for institution in institutions:
node_qs = institution.nodes.filter(
deleted__isnull=True,
created__date__lte=date,
).exclude(type='osf.registration')
registration_qs = institution.nodes.filter(
deleted__isnull=True,
created__date__lte=date,
type='osf.registration',
)

report = InstitutionDashboardSummaryReport(
report_date=date,
institution_id=institution._id,
institution_name=institution.name,
users=RunningTotal(
total=institution.get_institution_users().filter(is_active=True).count(),
total_daily=institution.get_institution_users().filter(date_confirmed__date=date).count(),
),
# Projects use get_roots to remove children
projects=NodeRunningTotals(
total=node_qs.get_roots().count(),
public=node_qs.filter(public_query).get_roots().count(),
private=node_qs.filter(private_query).get_roots().count(),

total_daily=node_qs.filter(daily_query).get_roots().count(),
public_daily=node_qs.filter(public_query & daily_query).get_roots().count(),
private_daily=node_qs.filter(private_query & daily_query).get_roots().count(),
),
registerations=RegistrationRunningTotals(
total=registration_qs.count(),
public=registration_qs.filter(public_query).count(),
embargoed=registration_qs.filter(private_query).count(),
embargoed_v2=registration_qs.filter(private_query & embargo_v2_query).count(),

total_daily=registration_qs.filter(daily_query).count(),
public_daily=registration_qs.filter(public_query & daily_query).count(),
embargoed_daily=registration_qs.filter(private_query & daily_query).count(),
embargoed_v2_daily=registration_qs.filter(private_query & daily_query & embargo_v2_query).count(),
),
files=FileRunningTotals(),
data=DataRunningTotals(),
)

reports.append(report)
return reports
87 changes: 87 additions & 0 deletions osf/metrics/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class RunningTotal(InnerDoc):
total = metrics.Integer()
total_daily = metrics.Integer()


class FileRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
Expand All @@ -102,6 +103,16 @@ class FileRunningTotals(InnerDoc):
public_daily = metrics.Integer()
private_daily = metrics.Integer()


class DataRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
private = metrics.Integer()
total_daily = metrics.Integer()
public_daily = metrics.Integer()
private_daily = metrics.Integer()


class NodeRunningTotals(InnerDoc):
total = metrics.Integer()
total_excluding_spam = metrics.Integer()
Expand All @@ -112,6 +123,18 @@ class NodeRunningTotals(InnerDoc):
public_daily = metrics.Integer()
private_daily = metrics.Integer()


class ProjectRootRunningTotals(InnerDoc):
total = metrics.Integer()
total_excluding_spam = metrics.Integer()
public = metrics.Integer()
private = metrics.Integer()
total_daily = metrics.Integer()
total_daily_excluding_spam = metrics.Integer()
public_daily = metrics.Integer()
private_daily = metrics.Integer()


class RegistrationRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
Expand All @@ -124,6 +147,15 @@ class RegistrationRunningTotals(InnerDoc):
embargoed_v2_daily = metrics.Integer()
withdrawn_daily = metrics.Integer()


class PreprintRunningTotals(InnerDoc):
total = metrics.Integer()
public = metrics.Integer()
withdrawn = metrics.Integer()
total_daily = metrics.Integer()
public_daily = metrics.Integer()
withdrawn_daily = metrics.Integer()

##### END reusable inner objects #####


Expand Down Expand Up @@ -168,6 +200,61 @@ class InstitutionSummaryReport(DailyReport):
registered_projects = metrics.Object(RegistrationRunningTotals)


class InstitutionDashboardSummaryReport(DailyReport):
"""
These are the following attributes necessary for the Institutional Dashboard Summary:
Counts
Users
Top-level Public projects*
Top-level Private projects*
Public registrations
Private registrations
preprints
Files
Data stored (both public and private; OSF storage only)
Tables
"""

DAILY_UNIQUE_FIELD = 'institution_id'

institution_id = metrics.Keyword()
institution_name = metrics.Keyword()
users = metrics.Object(RunningTotal)
projects = metrics.Object(NodeRunningTotals)
registrations = metrics.Object(RegistrationRunningTotals)
preprint = metrics.Object(PreprintRunningTotals)
files = metrics.Object(FileRunningTotals)
data = metrics.Object(DataRunningTotals)

# Visualizations
## Users by department pie chart
users_by_departments = metrics.Object()

## Line graph of recent user activity [Wip]

## Stacked bar chart showing types of OSF objects
types_of_resource = metrics.Object()

## simple bar chart showing public vs. private data
private_data = metrics.Integer()
public_data = metrics.Integer()

## Pie chart showing addons used
types_of_addons = metrics.Object(StorageAddonUsage)

## Pie chart of storage regions
storage_regions = metrics.Object()

## Pie chart of licenses
types_of_licenses = metrics.Object()

## FAIR assessment star plot (a star plot with each arm being the presence of a metadata element or identifier) or
# other FAIR metric? [WIP]

## Something to represent the size of projects … like a scatter plot? Each dot is a project and one axis is size of
# data, but not sure what the other axis would be


class NewUserDomainReport(DailyReport):
DAILY_UNIQUE_FIELD = 'domain_name'

Expand Down

0 comments on commit 176253a

Please sign in to comment.