├── .coveragerc
├── .env.example
├── .github
└── workflows
│ └── release.yaml
├── .gitignore
├── .gitlab-ci.yml
├── .gitlab
├── build-image.yml
├── build-vue.yml
├── github-export.yml
├── pre-commit.yml
├── run-tests.yml
├── sentry.yml
├── test-image.yml
└── test-js.yml
├── .pre-commit-config.yaml
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.rst
├── RELEASES.yaml
├── apps
├── activity
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_useractivity_plural.py
│ │ └── __init__.py
│ ├── models.py
│ ├── signals.py
│ ├── tests.py
│ └── views.py
├── annotations
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_no_title_no_report_type.py
│ │ ├── 0003_annotation_level.py
│ │ ├── 0004_annotation_owner_level.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_authorization.py
│ │ └── test_views.py
│ ├── translation.py
│ ├── urls.py
│ └── views.py
├── api
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── auth.py
│ ├── fake_data.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_requirement_update.py
│ │ └── __init__.py
│ ├── models.py
│ ├── permissions.py
│ ├── templates
│ │ └── api
│ │ │ └── redoc.html
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ └── test_platform_report_apiview_with_sushi.py
│ ├── throttling.py
│ ├── urls.py
│ └── views.py
├── charts
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── logic
│ │ └── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_chartdefinition_reportviewtocharttype.py
│ │ ├── 0003_chartdefinition_ignore_organization.py
│ │ ├── 0004_is_standard_view_and_position.py
│ │ ├── 0005_chartdefinition_ignore_platform.py
│ │ ├── 0006_chartdefinition_scope.py
│ │ ├── 0007_chartdefinition_scope_blank.py
│ │ ├── 0008_datasource_set_null.py
│ │ ├── 0009_jsonfield.py
│ │ ├── 0010_chartdefinition_is_generic.py
│ │ ├── 0011_remove_reportdataview_primary_dimension.py
│ │ ├── 0012_tr_j1_unique_item_requests.py
│ │ ├── 0013_redefine_standard_views.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ └── test_api.py
│ ├── translation.py
│ ├── urls.py
│ └── views.py
├── conftest.py
├── core
│ ├── __init__.py
│ ├── account.py
│ ├── admin.py
│ ├── admin_site.py
│ ├── apps.py
│ ├── auth.py
│ ├── authentication.py
│ ├── context_managers.py
│ ├── db.py
│ ├── exceptions.py
│ ├── fake_data.py
│ ├── fields.py
│ ├── filters.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── bins.py
│ │ ├── dates.py
│ │ ├── debug.py
│ │ ├── email.py
│ │ ├── error_reporting.py
│ │ ├── lookup_json_by_title.py
│ │ ├── management_commands.py
│ │ ├── maximus_sync.py
│ │ ├── serialization.py
│ │ ├── sync.py
│ │ ├── type_conversion.py
│ │ ├── url.py
│ │ └── util.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── cleanup_database.py
│ │ │ ├── create_users_from_csv.py
│ │ │ ├── echo.py
│ │ │ ├── erms_sync_identities_and_users.py
│ │ │ ├── lookup_json_by_title.py
│ │ │ ├── start_celery_task.py
│ │ │ ├── sync_logging_db.py
│ │ │ └── sync_maximus.py
│ ├── middleware.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_identity.py
│ │ ├── 0003_datasource.py
│ │ ├── 0004_identity_verbosename.py
│ │ ├── 0005_user_language.py
│ │ ├── 0006_blank_ext_id.py
│ │ ├── 0007_timestamps.py
│ │ ├── 0008_user_extra_data.py
│ │ ├── 0009_user_extra_data_default.py
│ │ ├── 0010_default_lang_change.py
│ │ ├── 0011_datasource_knowledgebase.py
│ │ ├── 0012_datasource_set_null.py
│ │ ├── 0013_jsonfield.py
│ │ ├── 0014_auto_20210329_1002.py
│ │ ├── 0015_unique_name_within_organization_data_source.py
│ │ ├── 0016_taskprogress.py
│ │ ├── 0017_user_extra_data_dismissed_and_seen_last_release.py
│ │ ├── 0018_pgcrypto.py
│ │ ├── 0019_alter_user_managers.py
│ │ ├── 0020_otp_devices.py
│ │ ├── 0021_user_skip_2fa.py
│ │ └── __init__.py
│ ├── models.py
│ ├── pagination.py
│ ├── permissions.py
│ ├── prometheus.py
│ ├── request_logging
│ │ ├── __init__.py
│ │ ├── capture.py
│ │ ├── celery_capture.py
│ │ └── clickhouse.py
│ ├── serializers.py
│ ├── signals.py
│ ├── static
│ │ └── __do_not_remove__.txt
│ ├── task_support.py
│ ├── tasks.py
│ ├── templates
│ │ ├── account
│ │ │ └── email
│ │ │ │ ├── email_confirmation_message.txt
│ │ │ │ ├── email_confirmation_signup_message.txt
│ │ │ │ ├── email_confirmation_signup_subject.txt
│ │ │ │ └── email_confirmation_subject.txt
│ │ └── registration
│ │ │ ├── invitation_email.html
│ │ │ ├── invitation_subject.txt
│ │ │ ├── password_reset_message.html
│ │ │ └── password_reset_subject.txt
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_admin.py
│ │ ├── test_api.py
│ │ ├── test_authentication.py
│ │ ├── test_logic_bins.py
│ │ ├── test_logic_dates.py
│ │ ├── test_lookup_json_by_title.py
│ │ ├── test_maximus_sync.py
│ │ ├── test_models.py
│ │ ├── test_request_logging.py
│ │ ├── test_sync.py
│ │ └── test_user_management.py
│ ├── urls.py
│ ├── validators.py
│ └── views.py
├── cost
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_payment_unique_together.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── urls.py
│ └── views.py
├── deployment
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_image_as_filefield.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ └── test_api.py
│ ├── urls.py
│ └── views.py
├── erms
│ ├── __init__.py
│ ├── api.py
│ ├── sync.py
│ └── tests
│ │ ├── conftest.py
│ │ └── test_erms.py
├── events
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── event_filters.py
│ ├── fake_data.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_alter_event_last_updated_by.py
│ │ ├── 0003_initial_info_event.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── signals.py
│ ├── tasks.py
│ ├── templates
│ │ └── events
│ │ │ ├── welcome_event_description.md
│ │ │ └── welcome_event_title.txt
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ ├── test_models.py
│ │ └── test_signals.py
│ ├── urls.py
│ └── views.py
├── export
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── enums.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20210329_1002.py
│ │ ├── 0003_created_autoaddnow.py
│ │ ├── 0004_export_status_error.py
│ │ ├── 0005_flexibledataexport_file_format.py
│ │ ├── 0006_alter_flexibledataexport_file_format.py
│ │ ├── 0007_flexibledataapiexport.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── signals.py
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api_and_tasks.py
│ │ └── test_flexibledataexport.py
│ ├── urls.py
│ └── views.py
├── impersonate_api
│ ├── __init__.py
│ ├── apps.py
│ ├── permissions.py
│ ├── serializers.py
│ ├── tests
│ │ └── test_api.py
│ ├── urls.py
│ └── views.py
├── knowledgebase
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── fetch_platforms_from_knowledgebase.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_jsonfield.py
│ │ ├── 0003_routersyncattempt.py
│ │ ├── 0004_report_type_in_knowledgebase.py
│ │ ├── 0005_nibbler.py
│ │ ├── 0006_alter_routersyncattempt_last_error.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── signals.py
│ ├── tasks.py
│ ├── templates
│ │ └── knowledgebase
│ │ │ └── importattempt_changelist.html
│ └── tests
│ │ ├── __init__.py
│ │ ├── test_models.py
│ │ └── test_tasks.py
├── logs
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── constants.py
│ ├── cubes.py
│ ├── exceptions.py
│ ├── fake_data.py
│ ├── fields.py
│ ├── filters.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── attempt_import.py
│ │ ├── cleanup.py
│ │ ├── clickhouse.py
│ │ ├── custom_import.py
│ │ ├── data_coverage.py
│ │ ├── data_import.py
│ │ ├── export.py
│ │ ├── export_analytical.py
│ │ ├── export_counter.py
│ │ ├── export_utils.py
│ │ ├── interest.py
│ │ ├── materialized_interest.py
│ │ ├── materialized_reports.py
│ │ ├── queries.py
│ │ ├── remap.py
│ │ ├── reporting
│ │ │ ├── __init__.py
│ │ │ ├── export.py
│ │ │ ├── filters.py
│ │ │ ├── helpers.py
│ │ │ └── slicer.py
│ │ └── split_fetch_intentions.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── check_interest_definitions.py
│ │ │ ├── check_materialized_report_types.py
│ │ │ ├── check_organizationplatforms.py
│ │ │ ├── check_report_type_dimensions.py
│ │ │ ├── compare_db_with_clickhouse.py
│ │ │ ├── compare_db_with_clickhouse_low_level.py
│ │ │ ├── convert_clickhouse_to_mergetree.py
│ │ │ ├── define_interest_for_all_platforms.py
│ │ │ ├── export_analytical.py
│ │ │ ├── export_fetch_attempts.py
│ │ │ ├── fetch_sushi5.py
│ │ │ ├── find_ibs_without_date.py
│ │ │ ├── find_split_records.py
│ │ │ ├── import_fetch_attempts.py
│ │ │ ├── recompute_interest.py
│ │ │ ├── recompute_materialized_reports.py
│ │ │ ├── remove_interest.py
│ │ │ ├── reporting_stats.py
│ │ │ ├── sync_clickhouse_db.py
│ │ │ ├── sync_interest.py
│ │ │ ├── sync_with_clickhouse.py
│ │ │ ├── test_export.py
│ │ │ ├── test_materialization_speed.py
│ │ │ └── title_reimport.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_add_dimension_sorting.py
│ │ ├── 0003_split_accesslog_source.py
│ │ ├── 0004_source_field.py
│ │ ├── 0005_metric_active.py
│ │ ├── 0006_metric_interest_group.py
│ │ ├── 0007_name_in_interest_group.py
│ │ ├── 0008_importbatch.py
│ │ ├── 0009_accesslog_import_batch.py
│ │ ├── 0010_verbose_name_plural.py
│ │ ├── 0011_richer_importbatch.py
│ │ ├── 0012_manualdataupload.py
│ │ ├── 0013_nullable_title_mdu_validation.py
│ │ ├── 0014_default_dimension_type.py
│ │ ├── 0015_change_data_file_validators.py
│ │ ├── 0016_report_interest_metrics.py
│ │ ├── 0017_virtual_report_types.py
│ │ ├── 0018_virtual_report_types_translation.py
│ │ ├── 0019_virtualreporttype_primary_dimension.py
│ │ ├── 0020_materialized_interest_support.py
│ │ ├── 0021_virtual_report_type_to_report_data_view.py
│ │ ├── 0022_move_some_models_to_charts.py
│ │ ├── 0023_importbatch_interest_processed.py
│ │ ├── 0024_no_reportinterestmetric_name.py
│ │ ├── 0025_modification_dates.py
│ │ ├── 0026_interest_group_ordering.py
│ │ ├── 0027_importbatch_interest_timestamp.py
│ │ ├── 0028_reporttype_superseeded_by.py
│ │ ├── 0029_remove_importbatch_interest_processed.py
│ │ ├── 0030_manualdataupload_owner_level.py
│ │ ├── 0031_add_accesslog_brin_indexes.py
│ │ ├── 0032_optimize_accesslog_indexes.py
│ │ ├── 0033_add_reportmaterializationspec.py
│ │ ├── 0034_importbatch_materialization_info.py
│ │ ├── 0035_reporttype_default_platform_interest.py
│ │ ├── 0036_datasource_set_null.py
│ │ ├── 0037_jsonfield.py
│ │ ├── 0038_flexiblereport.py
│ │ ├── 0038_reporttype_materialization_date.py
│ │ ├── 0039_dimension_constraints.py
│ │ ├── 0040_reporttype_approx_record_count.py
│ │ ├── 0041_merge_20210327_1013.py
│ │ ├── 0042_flexiblereport_last_updated_by.py
│ │ ├── 0043_flexireport_accesslevel_ownership.py
│ │ ├── 0044_better_source_related_constraints.py
│ │ ├── 0045_dimension_int_to_str.py
│ │ ├── 0046_one_import_batch_per_month.py
│ │ ├── 0047_importbatch_last_updated_clickhoused.py
│ │ ├── 0048_importbatchsynclog.py
│ │ ├── 0049_mdu_many_importbatches.py
│ │ ├── 0050_import_batch_date_remove_import_batch_from_mdu.py
│ │ ├── 0051_split_import_batches.py
│ │ ├── 0052_remove_importbatch_system_created.py
│ │ ├── 0053_clickhouse_add_import_batch_idx.py
│ │ ├── 0054_fill_importbatch_date.py
│ │ ├── 0055_accesslog_logs_access_platfor_cdb3c4_idx.py
│ │ ├── 0056_importbatch_logs_import_date_brin.py
│ │ ├── 0057_rename_extra_manualdataupload_preflight.py
│ │ ├── 0057_verbose_names.py
│ │ ├── 0058_manualdataupload_error.py
│ │ ├── 0059_manualdataupload_state.py
│ │ ├── 0060_controlled_metrics.py
│ │ ├── 0061_remove_manualdataupload_is_processed.py
│ │ ├── 0062_merge_20220325_1628.py
│ │ ├── 0063_alter_reportinterestmetric_interest_group.py
│ │ ├── 0064_manualdataupload_error_details.py
│ │ ├── 0065_remove_dimension_type.py
│ │ ├── 0066_lastaction.py
│ │ ├── 0067_alter_importbatchsynclog_state.py
│ │ ├── 0067_mdu_sourcefile_mixin.py
│ │ ├── 0068_file_checksums.py
│ │ ├── 0069_merge_20220603_1325.py
│ │ ├── 0070_reporttype_ext_id.py
│ │ ├── 0071_mdu_import_batch_ordering.py
│ │ ├── 0072_nibbler.py
│ │ ├── 0073_alter_reportinterestmetric_unique_together.py
│ │ ├── 0074_mdu_method.py
│ │ ├── 0075_multimedia_interest.py
│ │ ├── 0076_deduplicate_metrics.py
│ │ ├── 0077_remove_source_from_dimension.py
│ │ ├── 0078_remove_organizationplatform_sushi_credentials.py
│ │ ├── 0079_alter_importbatch_unique_together.py
│ │ ├── 0080_alter_organizationplatform_unique_together.py
│ │ ├── 0081_mdu_extra_and_constraints.py
│ │ ├── 0082_importbatch_manual_empty.py
│ │ ├── 0083_alter_importbatchsynclog_last_updated_by_and_more.py
│ │ ├── 0084_accesslog_item_and_dim8.py
│ │ ├── 0085_interestgroup_implies_availability.py
│ │ ├── 0086_flexiblereport_created_by_and_more.py
│ │ ├── 0087_remove_reporttype_superseeded_by_and_more.py
│ │ └── __init__.py
│ ├── models.py
│ ├── permissions.py
│ ├── serializers.py
│ ├── signals.py
│ ├── static
│ │ └── css
│ │ │ └── report_type.css
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── data
│ │ ├── test_api.py
│ │ ├── test_api_export_counter.py
│ │ ├── test_api_flexiblereport.py
│ │ ├── test_api_flexibleslicer.py
│ │ ├── test_api_importbatch.py
│ │ ├── test_api_manualdataupload.py
│ │ ├── test_attempt_import.py
│ │ ├── test_check_materialized_report_types.py
│ │ ├── test_check_report_type_dimensions.py
│ │ ├── test_cleanup.py
│ │ ├── test_clickhouse.py
│ │ ├── test_custom_import.py
│ │ ├── test_data_deleting.py
│ │ ├── test_data_import.py
│ │ ├── test_export_analytical.py
│ │ ├── test_export_counter.py
│ │ ├── test_export_utils.py
│ │ ├── test_fetch_intention_splitting_migration.py
│ │ ├── test_flexibledataslicer.py
│ │ ├── test_interest_calculation.py
│ │ ├── test_last_action.py
│ │ ├── test_manualdataupload_authorization.py
│ │ ├── test_materialized_reports.py
│ │ ├── test_migrations.py
│ │ ├── test_models.py
│ │ ├── test_models_manualdataupload.py
│ │ └── test_title_reimport.py
│ ├── translation.py
│ ├── urls.py
│ └── views.py
├── necronomicon
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_drop_fk_for_task_result.py
│ │ ├── 0003_alter_batch_status_and_add_prepared_deleted.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tasks.py
│ ├── templates
│ │ └── necronomicon
│ │ │ └── admin
│ │ │ └── change_form.html
│ └── tests
│ │ ├── test_models.py
│ │ └── test_tasks.py
├── nibbler
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── dict_reader.py
│ │ ├── processing.py
│ │ └── utils.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── nigiri_vs_nibbler.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_parserdefinition_platforms.py
│ │ └── __init__.py
│ └── models.py
├── organizations
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── queries.py
│ │ └── sync.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── create_organization_api_keys.py
│ │ │ ├── create_organizations_from_csv.py
│ │ │ ├── delete_organization.py
│ │ │ ├── erms_sync_organizations.py
│ │ │ ├── load_sushi_credentials.py
│ │ │ └── load_sushi_credentials_from_xlsx.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_nullable_internal_id.py
│ │ ├── 0003_non_unique_ico.py
│ │ ├── 0004_organization_source.py
│ │ ├── 0005_organization_users.py
│ │ ├── 0006_organization_platforms.py
│ │ ├── 0007_sushicredentials.py
│ │ ├── 0008_sushicredentials_enabled.py
│ │ ├── 0009_sushi_credentials_tuning.py
│ │ ├── 0010_delete_sushicredentials.py
│ │ ├── 0011_userorganization_source.py
│ │ ├── 0012_timestamps.py
│ │ ├── 0013_auto_20191113_0939.py
│ │ ├── 0014_nullable_ico.py
│ │ ├── 0015_nullable_ext_id.py
│ │ ├── 0016_more_blank_fields.py
│ │ ├── 0017_add_organizationaltname.py
│ │ ├── 0018_datasource_set_null.py
│ │ ├── 0019_jsonfield.py
│ │ ├── 0020_organization_unique_shortname.py
│ │ ├── 0021_alter_organization_options.py
│ │ ├── 0022_organization_raw_enabled.py
│ │ ├── 0023_alter_organizationaltname_options.py
│ │ ├── 0024_alter_userorganization_unique_together.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ ├── test_db.py
│ │ ├── test_logic_sync.py
│ │ └── test_models.py
│ ├── translation.py
│ ├── urls.py
│ └── views.py
├── publications
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── filters.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── arrival_probabilities.py
│ │ ├── cleanup.py
│ │ ├── item_management.py
│ │ ├── knowledgebase.py
│ │ ├── sync.py
│ │ ├── title_list_overlap.py
│ │ ├── title_management.py
│ │ ├── use_cases.py
│ │ └── validation.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── cleanup_obsolete_platformtitles.py
│ │ │ ├── create_platforms_from_csv.py
│ │ │ ├── erms_sync_platforms.py
│ │ │ ├── export_platforms.py
│ │ │ ├── get_arrival_probabilities.py
│ │ │ ├── load_registry_ids_from_csv.py
│ │ │ ├── merge_titles.py
│ │ │ ├── normalize_titles.py
│ │ │ ├── remove_unused_titles.py
│ │ │ ├── sync_pub_types_with_accesslogs.py
│ │ │ └── update_arrival_curves.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_title_doi.py
│ │ ├── 0003_nullable_title_attrs.py
│ │ ├── 0004_pub_type_verbose_name.py
│ │ ├── 0005_auto_20190801_1615.py
│ │ ├── 0006_no_null_title_text_attrs.py
│ │ ├── 0007_title_unique_together.py
│ │ ├── 0008_more_pub_types.py
│ │ ├── 0009_even_more_pub_types.py
│ │ ├── 0010_platform_interest_reports.py
│ │ ├── 0011_unlocalize_short_name.py
│ │ ├── 0012_platform_source.py
│ │ ├── 0013_platforminterestreport_m2m.py
│ │ ├── 0014_remove_old_interest_reports_attr.py
│ │ ├── 0015_platformtitle.py
│ │ ├── 0016_title_trgm_index.py
│ │ ├── 0017_platformtitle_unique_data.py
│ │ ├── 0018_platformtitle_unique_constraint.py
│ │ ├── 0019_more_pub_types.py
│ │ ├── 0020_platform_nullable_ext_id.py
│ │ ├── 0021_platform_knowledgebase.py
│ │ ├── 0022_datasource_set_null.py
│ │ ├── 0023_jsonfield.py
│ │ ├── 0024_better_source_related_constraints.py
│ │ ├── 0025_platform_unique_shortname.py
│ │ ├── 0026_title_type_data_migration.py
│ │ ├── 0027_fill_platform_name.py
│ │ ├── 0028_title_uris_proprietary_ids.py
│ │ ├── 0028_verbose_names.py
│ │ ├── 0029_title_default_pub_type.py
│ │ ├── 0030_merge_0028_verbose_names_0029_title_default_pub_type.py
│ │ ├── 0031_alter_title_unique_together.py
│ │ ├── 0032_counter_registry_id.py
│ │ ├── 0033_platform_duplicates.py
│ │ ├── 0034_issn_renormalization.py
│ │ ├── 0035_alter_platform_source.py
│ │ ├── 0036_titleoverlapbatch.py
│ │ ├── 0037_add_ir_m1_interest_to_all_platforms.py
│ │ ├── 0038_issn_eissn_index.py
│ │ ├── 0039_alter_titleoverlapbatch_last_updated_by.py
│ │ ├── 0040_alter_title_unique_together.py
│ │ ├── 0041_item.py
│ │ ├── 0042_platform_sushi_arrival_stats.py
│ │ ├── 0043_remove_platform_ext_id_source_null_and_more.py
│ │ ├── 0044_alter_authortoitem_options_author_created_and_more.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ ├── test_cleanup.py
│ │ ├── test_commands.py
│ │ ├── test_item_manager.py
│ │ ├── test_merge_titles.py
│ │ ├── test_models.py
│ │ ├── test_sync.py
│ │ ├── test_tasks.py
│ │ ├── test_title_data_validation.py
│ │ ├── test_title_list_overlap.py
│ │ └── test_title_manager.py
│ ├── translation.py
│ ├── urls.py
│ └── views.py
├── recache
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ └── refresh_recache_from_older_django.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_add_stats.py
│ │ ├── 0003_cachedquery_origin.py
│ │ ├── 0004_unique_query_hash.py
│ │ ├── 0005_remove_cachedquery_query_pickle.py
│ │ ├── 0006_query_hash_unique_with_django_version.py
│ │ ├── 0007_alter_cachedquery_lifetime.py
│ │ ├── 0008_remove_obsolete_caches.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── test_models.py
│ │ └── test_util.py
│ ├── util.py
│ └── views.py
├── releases
│ ├── __init__.py
│ ├── apps.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── changelog.py
│ │ └── releases.py
│ ├── migrations
│ │ └── __init__.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ └── test_parsers.py
│ ├── urls.py
│ └── views.py
├── reporting
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── conftest.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── computation.py
│ │ ├── export.py
│ │ ├── parsing.py
│ │ └── report_definitions.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── test_api.py
│ │ ├── test_parsing.py
│ │ └── test_platform_reports.py
│ ├── urls.py
│ └── views.py
├── scheduler
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── filters
│ │ ├── __init__.py
│ │ ├── harvests.py
│ │ └── intentions.py
│ ├── logic
│ │ ├── __init__.py
│ │ └── automatic.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_fetchintention_duplicit_of.py
│ │ ├── 0003_harvest.py
│ │ ├── 0004_automatic.py
│ │ ├── 0005_fetchintention_date_constraint.py
│ │ ├── 0006_fetchintention_retry_id.py
│ │ ├── 0007_fetchintention_one_to_one_attempt.py
│ │ ├── 0008_current_task.py
│ │ ├── 0009_rename_retry_id_to_queue_id.py
│ │ ├── 0010_fetchintention_canceled.py
│ │ ├── 0011_fetchintention_previous.py
│ │ ├── 0012_fill_queue_id.py
│ │ ├── 0013_fetch_intention_queue.py
│ │ ├── 0014_finalizing_import_batch.py
│ │ ├── 0015_fetchintention_timestamp.py
│ │ ├── 0016_fix_fi_queues.py
│ │ ├── 0017_alter_scheduler_cooldown.py
│ │ ├── 0018_alter_harvest_last_updated_by.py
│ │ ├── 0019_alter_scheduler_too_many_requests_delay.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── signals.py
│ ├── tasks.py
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_api.py
│ │ └── test_models.py
│ ├── urls.py
│ └── views.py
├── sushi
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── logic
│ │ ├── __init__.py
│ │ ├── cleanup.py
│ │ ├── data_import.py
│ │ └── export.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── __init__.py
│ │ │ ├── assign_reports_to_credentials.py
│ │ │ ├── change_credentials_url.py
│ │ │ ├── check_reimport.py
│ │ │ ├── cleanup_fetch_attempts.py
│ │ │ ├── create_fake_sushi_for_demo.py
│ │ │ ├── credentials_with_mismatched_url.py
│ │ │ ├── find_missing_attempt_files.py
│ │ │ ├── load_platform_report_table.py
│ │ │ ├── remove_orphaned_files.py
│ │ │ └── validate_sushi_json.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_sushifetchattempt.py
│ │ ├── 0003_counterreporttype_active.py
│ │ ├── 0004_processing_info.py
│ │ ├── 0005_attemp_queuing.py
│ │ ├── 0006_sushicredentials_active_counter_reports.py
│ │ ├── 0007_sushifetchattempt_import_batch.py
│ │ ├── 0008_sushiattemp_importbatch_onetoone.py
│ │ ├── 0009_conterreporttype_oneonone_report_type.py
│ │ ├── 0010_counterreporttype_code_choices.py
│ │ ├── 0011_sushifetchattempt_error_code.py
│ │ ├── 0012_sushifetchattempt_contains_data.py
│ │ ├── 0013_auto_20190829_1105.py
│ │ ├── 0014_sushifetchattempt_processing_success.py
│ │ ├── 0015_help_text.py
│ │ ├── 0016_counterreporttype_superseeded_by.py
│ │ ├── 0017_sushifetchattempt_processing_info.py
│ │ ├── 0018_sushifetchattempt_in_progress.py
│ │ ├── 0019_add_defaults_to_sushifetchattempt_booleans.py
│ │ ├── 0020_remove_JR5_counter_report.py
│ │ ├── 0021_sushifetchattempt_import_crashed.py
│ │ ├── 0022_sushi_credentials_locking.py
│ │ ├── 0023_sushicredentials_last_updated_by.py
│ │ ├── 0024_lock_level_change.py
│ │ ├── 0025_remove_counterreporttype_superseeded_by.py
│ │ ├── 0026_customer_id_requestor_id_blank_fix.py
│ │ ├── 0027_queue_previous_reverse_name.py
│ │ ├── 0028_sushifetchattempt_credentials_version_hash.py
│ │ ├── 0029_sushicredentials_version_hash.py
│ │ ├── 0030_sushicredentials_title.py
│ │ ├── 0031_sushifetchattempt_last_updated.py
│ │ ├── 0032_unschedule_3030.py
│ │ ├── 0033_sushifetchattempt_queue_id.py
│ │ ├── 0034_longer_data_file_field.py
│ │ ├── 0035_sushifetchattempt_http_status_code.py
│ │ ├── 0036_credentials_intermediate_report_types.py
│ │ ├── 0037_broken_credentials.py
│ │ ├── 0038_jsonfield.py
│ │ ├── 0039_remove_http_auth_from_c5.py
│ │ ├── 0040_broken_blank_true.py
│ │ ├── 0041_more_report_types.py
│ │ ├── 0042_counterreporttype_code_update.py
│ │ ├── 0043_sushifetchattempt_partial_data.py
│ │ ├── 0044_fix_data_already_imported.py
│ │ ├── 0045_fetchattempt_statemachine.py
│ │ ├── 0046_fetchintentions_for_fetch_attempts.py
│ │ ├── 0047_no_data_for_3031_and_3030.py
│ │ ├── 0048_discard_credentials_broken_state.py
│ │ ├── 0049_sushifetchattempt_extracted_data.py
│ │ ├── 0050_alter_sushicredentials_api_key.py
│ │ ├── 0051_fetchattempt_remove_queue_stuff.py
│ │ ├── 0052_select_best_empty_importbatch.py
│ │ ├── 0053_sourcefile_mixin.py
│ │ ├── 0054_file_checksums.py
│ │ ├── 0055_fill_missing_extracted_data.py
│ │ ├── 0056_alter_sushifetchattempt_credentials.py
│ │ ├── 0057_alter_sushifetchattempt_status.py
│ │ ├── 0058_help_text_fix.py
│ │ ├── 0059_credentials_last_harvestable_month.py
│ │ ├── 0060_alter_sushicredentials_last_updated_by.py
│ │ ├── 0061_sushicredentials_auto_update_url_and_more.py
│ │ ├── 0062_sushifetchattempt_clashing_import_batch.py
│ │ ├── 0063_alter_counterreporttype_code.py
│ │ ├── 0064_sushifetchattempt_sushi_url.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── static
│ │ └── admin
│ │ │ └── admin.css
│ ├── tasks.py
│ ├── templates
│ │ ├── Template_for_SushiCredentials_import_consortium.xlsx
│ │ └── Template_for_SushiCredentials_import_singleorg.xlsx
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── data
│ │ ├── test_api.py
│ │ ├── test_arrival_probabilities.py
│ │ ├── test_commands.py
│ │ ├── test_fetching.py
│ │ ├── test_logic_data_import.py
│ │ ├── test_sushi_fetching.py
│ │ ├── test_sushicredentials_model.py
│ │ ├── test_sushifetchattempt_model.py
│ │ ├── test_tasks.py
│ │ └── test_views.py
│ ├── urls.py
│ └── views.py
└── tags
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── fake_data.py
│ ├── filters.py
│ ├── logic
│ ├── __init__.py
│ └── titles_lists.py
│ ├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ ├── create_fake_title_tags.py
│ │ ├── tag_title_list.py
│ │ └── test_tag_performance.py
│ ├── migrations
│ ├── 0001_initial.py
│ ├── 0002_tagclass_defaults_for_tag.py
│ ├── 0003_tagging_batch.py
│ ├── 0004_alter_taggingbatch_state.py
│ ├── 0005_alter_tag_options.py
│ ├── 0006_tagging_batch_cascade.py
│ ├── 0007_tagging_batch_internal_name.py
│ ├── 0008_alter_taggingbatch_source_file.py
│ ├── 0009_usertagclass.py
│ ├── 0010_tagging_attempts_and_more.py
│ ├── 0011_recreate_tag_constraints.py
│ ├── 0012_alter_organizationtag_last_updated_by_and_more.py
│ └── __init__.py
│ ├── models.py
│ ├── permissions.py
│ ├── serializers.py
│ ├── tasks.py
│ ├── tests
│ ├── __init__.py
│ ├── test_batch_tagging.py
│ ├── test_logic_title_lists.py
│ ├── test_models.py
│ └── test_views.py
│ ├── urls.py
│ └── views.py
├── bootstrap.sh
├── ci
└── Dockerfile
├── config
├── __init__.py
├── celery_conf.py
├── permissions.py
├── production.wsgi
├── settings
│ ├── __init__.py
│ ├── base.py
│ ├── devel.py
│ ├── docker.py
│ ├── production.py
│ ├── staging.py
│ └── test.py
├── staging.wsgi
├── urls.py
└── wsgi.py
├── create_fixtures.sh
├── data
├── TestFlexibleDataSlicer.csv
└── initial-data.json
├── design
└── ui
│ ├── .babelrc
│ ├── .env
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── jest.config.js
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ ├── favicon.png
│ ├── index.html
│ └── maintenance.html
│ ├── specs
│ ├── CheckMark.spec.js
│ ├── SushiCredentialsEditDialog.spec.js-disabled
│ ├── dates.spec.js
│ ├── fetch-intention-states.spec.js
│ └── sushi-validation.spec.js
│ ├── src
│ ├── assets
│ │ ├── MSMT_cz.svg
│ │ ├── MSMT_cz_opt.svg
│ │ ├── celus-dark.png
│ │ ├── celus-horizontal-dark.svg
│ │ ├── celus-one-v1-dark.svg
│ │ ├── celus-one-v3-dark.svg
│ │ ├── celus-plus-dark.svg
│ │ ├── celus-plus-white-vertical-nobg.svg
│ │ ├── czechelib-stats-64.svg
│ │ ├── czechelib-stats.svg
│ │ ├── czechelib.svg
│ │ ├── czechelib_logo-mini_color-transp.png
│ │ ├── eu-96.png
│ │ ├── eu-large.png
│ │ ├── eu.png
│ │ ├── eu_fond.svg
│ │ ├── eu_fond_plain.svg
│ │ ├── ex-metric.png
│ │ ├── ex-title-metric-publisher-success.png
│ │ ├── ex-title.png
│ │ ├── hungry-celus-240.png
│ │ ├── hungry-celus.png
│ │ ├── ntk-96.svg
│ │ ├── sushi_credentials-enable.png
│ │ ├── sushi_credentials-test.png
│ │ └── sushi_credentials.png
│ ├── components
│ │ ├── AccessLogList.vue
│ │ ├── AddAnnotationButton.vue
│ │ ├── AddPlatformButton.vue
│ │ ├── AnnotationCreateModifyWidget.vue
│ │ ├── AnnotationList.vue
│ │ ├── AnnotationsWidget.vue
│ │ ├── BootUpWidget.vue
│ │ ├── CancelSimulationWidget.vue
│ │ ├── ChartDataTable.vue
│ │ ├── ChartTypeSelector.vue
│ │ ├── CounterDataExportWidget.vue
│ │ ├── CustomUploadInfoWidget.vue
│ │ ├── DataExportWidget.vue
│ │ ├── DateRangeSelector.vue
│ │ ├── EditPriceDialog.vue
│ │ ├── HarvestsTable.vue
│ │ ├── HoverText.vue
│ │ ├── ImportBatchChart.vue
│ │ ├── ImportBatchesDeleteConfirm.vue
│ │ ├── ImportBatchesList.vue
│ │ ├── ImportPreflightDataWidget.vue
│ │ ├── InterestOverviewMetrics.vue
│ │ ├── InterestOverviewReports.vue
│ │ ├── MDUChart.vue
│ │ ├── ManualUploadButton.vue
│ │ ├── ManualUploadListTable.vue
│ │ ├── ManualUploadState.vue
│ │ ├── NewCelusVersionDialog.vue
│ │ ├── OrganizationList.vue
│ │ ├── OrganizationPlatformInterestHeatmap.vue
│ │ ├── OverlapPyramidWidget.vue
│ │ ├── PlatformCostList.vue
│ │ ├── PlatformEditDialog.vue
│ │ ├── PlatformInterestChart.vue
│ │ ├── PlatformList.vue
│ │ ├── PlatformOverlapTable.vue
│ │ ├── PlatformVsAllOverlapTable.vue
│ │ ├── RawDataExportWidget.vue
│ │ ├── ReleaseCard.vue
│ │ ├── ReportInterestGroups.vue
│ │ ├── ReportTypeExamples.vue
│ │ ├── ReportTypeInfoWidget.vue
│ │ ├── SelectedDateRangeWidget.vue
│ │ ├── ShortenText.vue
│ │ ├── SupportedNonCounterPlatformsList.vue
│ │ ├── TitleList.vue
│ │ ├── TitleTypeFilterWidget.vue
│ │ ├── TopTenDashboardWidget.vue
│ │ ├── UndefinedInterestWidget.vue
│ │ ├── account
│ │ │ ├── AccountCreateModifyWidget.vue
│ │ │ ├── CreateOrganizationDialog.vue
│ │ │ ├── LoginDialog.vue
│ │ │ ├── OtpDialog.vue
│ │ │ └── PasswordChangeDialog.vue
│ │ ├── admin
│ │ │ ├── DeletePlatformDataWidget.vue
│ │ │ ├── ManagementCommand.vue
│ │ │ ├── ManagementCommandList.vue
│ │ │ └── ReportViewToChartManagementWidget.vue
│ │ ├── charts
│ │ │ ├── APIChart.vue
│ │ │ ├── CounterChartSet.vue
│ │ │ ├── CoverageMap.vue
│ │ │ ├── CoverageOverviewWidget.vue
│ │ │ ├── CoverageScoreGauge.vue
│ │ │ ├── SushiArrivalCurve.vue
│ │ │ └── SushiStatusChart.vue
│ │ ├── coverage
│ │ │ └── CoverageCard.vue
│ │ ├── events
│ │ │ ├── EventCategoryMark.vue
│ │ │ ├── EventCategorySelect.vue
│ │ │ ├── EventImportanceIcon.vue
│ │ │ ├── EventImportanceSelect.vue
│ │ │ └── EventList.vue
│ │ ├── items
│ │ │ └── ItemList.vue
│ │ ├── overlap
│ │ │ ├── TitleOverlapBatchList.vue
│ │ │ └── TitleOverlapUploadFileDialog.vue
│ │ ├── reporting
│ │ │ ├── AccessLevelSelector.vue
│ │ │ ├── CopyReportDialog.vue
│ │ │ ├── ExportOverviewTable.vue
│ │ │ ├── FilterCard.vue
│ │ │ ├── FilterSpec.vue
│ │ │ ├── FlexiTableEditor.vue
│ │ │ ├── FlexiTableOutput.vue
│ │ │ ├── MetricChip.vue
│ │ │ ├── ReportChip.vue
│ │ │ ├── ReportLoadingWidget.vue
│ │ │ ├── ReportNamingWidget.vue
│ │ │ ├── ReportSpecOverview.vue
│ │ │ ├── ReportingChart.vue
│ │ │ ├── StoredReportsTable.vue
│ │ │ └── TrendArrow.vue
│ │ ├── selectors
│ │ │ ├── DimensionKeySelector.vue
│ │ │ ├── InterestGroupSelector.vue
│ │ │ ├── OrganizationSelectionWidget.vue
│ │ │ ├── OrganizationSelector.vue
│ │ │ ├── PlatformSelectionWidget.vue
│ │ │ ├── PlatformSelector.vue
│ │ │ └── ReportViewSelector.vue
│ │ ├── special
│ │ │ ├── ReportPartParams.vue
│ │ │ ├── SpecializedReport.vue
│ │ │ └── SpecializedReportPart.vue
│ │ ├── sushi
│ │ │ ├── AttemptExtractedData.vue
│ │ │ ├── CounterReportLastHarvestableMonthWidget.vue
│ │ │ ├── DeleteSushiCredentialsDataWidget.vue
│ │ │ ├── FetchAttemptModeFilter.vue
│ │ │ ├── FetchIntentionStatusIcon.vue
│ │ │ ├── HarvestSelectedWidget.vue
│ │ │ ├── HarvesterIPAddressList.vue
│ │ │ ├── IconButton.vue
│ │ │ ├── IntroVideo.vue
│ │ │ ├── LastHarvestableMonthEntryWidget.vue
│ │ │ ├── RegistryIcon.vue
│ │ │ ├── SushiAttemptListWidget.vue
│ │ │ ├── SushiCredentialsDataDialog.vue
│ │ │ ├── SushiCredentialsEditDialog.vue
│ │ │ ├── SushiCredentialsManagementWidget.vue
│ │ │ ├── SushiCredentialsMonthOverviewWidget.vue
│ │ │ ├── SushiCredentialsOverviewHeaderWidget.vue
│ │ │ ├── SushiFetchIntentionStateIcon.vue
│ │ │ ├── SushiFetchIntentionsListWidget.vue
│ │ │ ├── SushiHarvestedSlotsWidget.vue
│ │ │ ├── SushiMarkAsEmptyWidget.vue
│ │ │ ├── SushiMonthStatusIcon.vue
│ │ │ ├── SushiReportIndicator.vue
│ │ │ └── SushiStatsDashboardWidget.vue
│ │ ├── tagging-batches
│ │ │ ├── TaggingAttemptList.vue
│ │ │ ├── TaggingBatchList.vue
│ │ │ ├── TaggingBatchProcessingWidget.vue
│ │ │ ├── TaggingBatchStateWidget.vue
│ │ │ └── TaggingBatchStats.vue
│ │ ├── tags
│ │ │ ├── AddTagButton.vue
│ │ │ ├── AddTagClassButton.vue
│ │ │ ├── EditTagClassWidget.vue
│ │ │ ├── EditTagWidget.vue
│ │ │ ├── TagAccessLevelSelector.vue
│ │ │ ├── TagCard.vue
│ │ │ ├── TagChip.vue
│ │ │ ├── TagChipSimple.vue
│ │ │ ├── TagClassScopeWidget.vue
│ │ │ ├── TagClassSelector.vue
│ │ │ ├── TagListWidget.vue
│ │ │ └── TagSelector.vue
│ │ ├── tasks
│ │ │ └── ServerTaskMonitor.vue
│ │ └── util
│ │ │ ├── AsColumnCheckbox.vue
│ │ │ ├── CheckMark.vue
│ │ │ ├── ColorEntry.vue
│ │ │ ├── CompositionBar.vue
│ │ │ ├── DateRangeText.vue
│ │ │ ├── DateWithTooltip.vue
│ │ │ ├── DoiLink.vue
│ │ │ ├── ErrorDialog.vue
│ │ │ ├── ErrorPlaceholder.vue
│ │ │ ├── ExportMonitorWidget.vue
│ │ │ ├── FromToMonthEntry.vue
│ │ │ ├── FromToYearEntry.vue
│ │ │ ├── GoodBadMark.vue
│ │ │ ├── ItemBadge.vue
│ │ │ ├── LargeSpinner.vue
│ │ │ ├── LoaderWidget.vue
│ │ │ ├── MenuListItem.vue
│ │ │ ├── MonthEntry.vue
│ │ │ ├── SimpleCompare.vue
│ │ │ ├── SimplePie.vue
│ │ │ ├── SmallLoader.vue
│ │ │ ├── TwoPaneSelector.vue
│ │ │ └── YearEntry.vue
│ ├── i18n.js
│ ├── libs
│ │ ├── attempt-state.js
│ │ ├── charts.js
│ │ ├── counter_header.js
│ │ ├── curve.js
│ │ ├── data-state.js
│ │ ├── dates.js
│ │ ├── db-object-localization.js
│ │ ├── dimensions.js
│ │ ├── email-validation.js
│ │ ├── flexi-reports.js
│ │ ├── group-ids.js
│ │ ├── http.js
│ │ ├── id-translation.js
│ │ ├── intention-state.js
│ │ ├── interest.js
│ │ ├── numbers.js
│ │ ├── organizations.js
│ │ ├── palettes.js
│ │ ├── pivot.js
│ │ ├── pub-types.js
│ │ ├── reporting-interface.js
│ │ ├── serialization.js
│ │ ├── server-task.js
│ │ ├── sleep.js
│ │ ├── sorting.js
│ │ ├── sources.js
│ │ ├── strings.js
│ │ ├── sushi-validation.js
│ │ ├── tags.js
│ │ ├── unique-mapping.js
│ │ └── user.js
│ ├── locales
│ │ ├── annotations.yaml
│ │ ├── charts.yaml
│ │ ├── common.yaml
│ │ ├── dialog.yaml
│ │ ├── en.json
│ │ ├── errors.yaml
│ │ ├── notifications.yaml
│ │ ├── pub-types.yaml
│ │ ├── reporting.yaml
│ │ ├── sources.yaml
│ │ └── sushi.yaml
│ ├── main.js
│ ├── mixins
│ │ ├── cancellation.js
│ │ ├── dimensions.js
│ │ ├── formRulesMixin.js
│ │ ├── reportTypes.js
│ │ ├── stateTracking.js
│ │ ├── tagAccessLevels.js
│ │ ├── tagColors.js
│ │ ├── tags.js
│ │ └── translators.js
│ ├── pages
│ │ ├── AccountManagementPage.vue
│ │ ├── AllTitlesListPage.vue
│ │ ├── AnnotationListPage.vue
│ │ ├── ChangeLogPage.vue
│ │ ├── CustomDataUploadPage.vue
│ │ ├── DashboardPage.vue
│ │ ├── DataCoverageOverviewPage.vue
│ │ ├── EmailNotVerified.vue
│ │ ├── EventsPage.vue
│ │ ├── ExportOverviewPage.vue
│ │ ├── FlexiTablePage.vue
│ │ ├── FlexibleReportsPage.vue
│ │ ├── HarvestsPage.vue
│ │ ├── InterestOverviewPage.vue
│ │ ├── InvalidUserPage.vue
│ │ ├── ItemDetailPage.vue
│ │ ├── Main.vue
│ │ ├── MaintenancePage.vue
│ │ ├── ManagementCommandsPage.vue
│ │ ├── ManagementPage.vue
│ │ ├── ManualUploadListPage.vue
│ │ ├── NotFoundPage.vue
│ │ ├── OrganizationListPage.vue
│ │ ├── OrganizationPlatformInterestOverviewPage.vue
│ │ ├── OverallCoverageDashboardWidget.vue
│ │ ├── OverlapAnalysisPage.vue
│ │ ├── PasswordResetPage.vue
│ │ ├── PlatformDetailPage.vue
│ │ ├── PlatformListPage.vue
│ │ ├── PlatformOverlapAnalysisPage.vue
│ │ ├── PlatformOverviewWidget.vue
│ │ ├── ReleasesPage.vue
│ │ ├── SidePanel.vue
│ │ ├── SpecializedReportsPage.vue
│ │ ├── StandardLayout.vue
│ │ ├── SupportedNonCounterPlatformsPage.vue
│ │ ├── SushiCredentialsManagementPage.vue
│ │ ├── SushiCredentialsMonthOverviewPage.vue
│ │ ├── SushiTroubleshootingPage.vue
│ │ ├── TagListPage.vue
│ │ ├── TaggingBatchesPage.vue
│ │ ├── TitleDetailPage.vue
│ │ ├── TitleListOverlapPage.vue
│ │ ├── UserPage.vue
│ │ └── VerifyEmailPage.vue
│ ├── plugins
│ │ └── vuetify.js
│ ├── router
│ │ └── index.js
│ ├── store
│ │ ├── index.js
│ │ └── modules
│ │ │ ├── cancellation.js
│ │ │ ├── events.js
│ │ │ ├── interest.js
│ │ │ ├── login.js
│ │ │ ├── maintenance.js
│ │ │ ├── page-settings.js
│ │ │ └── site-config.js
│ └── workers
│ │ └── event-worker.js
│ ├── vue.config.js
│ └── yarn.lock
├── docker
├── docker-compose-k8s.yml
├── docker-compose.yml
├── entrypoint-celery-beat.sh
├── entrypoint-celery.py
├── entrypoint-web.sh
├── env.list
└── nginx.conf
├── docs
├── Makefile
├── Uživatelská dokumentace.odt
├── admin.rst
├── advanced-topics.rst
├── ansible
│ ├── celus.yaml
│ ├── host_vars
│ │ └── example.com
│ │ │ └── vars
│ └── roles
│ │ └── celus
│ │ ├── defaults
│ │ └── main.yml
│ │ ├── handlers
│ │ └── main.yaml
│ │ ├── tasks
│ │ ├── celery.yaml
│ │ ├── django.yaml
│ │ ├── main.yaml
│ │ └── postgres.yaml
│ │ └── templates
│ │ ├── etc_confd_celery.j2
│ │ ├── etc_confd_celerybeat.j2
│ │ ├── etc_cron_daily_backup_db.j2
│ │ ├── etc_cron_daily_cleanup_django_sessions.j2
│ │ ├── etc_logrotated_celery.j2
│ │ ├── etc_profiled_virtualenvwrapper.sh.j2
│ │ ├── etc_systemd_system_celery.service.j2
│ │ ├── etc_systemd_system_celerybeat.service.j2
│ │ ├── root_activate_virtualenv.sh.j2
│ │ └── secret_settings.json.j2
├── conf.py
├── examples
│ ├── ex-just-values.csv
│ ├── ex-just-values.ods
│ ├── ex-metric.csv
│ ├── ex-metric.ods
│ ├── ex-metric.png
│ ├── ex-title-metric-publisher-success.ods
│ ├── ex-title-metric-publisher-success.png
│ ├── ex-title-metric-publisher.ods
│ ├── ex-title.ods
│ └── ex-title.png
├── external-api.rst
├── images
│ ├── api-key-create.png
│ ├── api-key-get-value.png
│ ├── dashboard.png
│ ├── dja_add_chart_definition.png
│ ├── dja_add_dimension.png
│ ├── dja_add_report_data_view.png
│ ├── dja_add_report_type.png
│ ├── dja_add_report_type_filled.png
│ ├── dja_add_report_view_to_chart_type.png
│ ├── dja_report_data_view_tr_jr1.png
│ ├── dja_sushi_app.png
│ ├── dja_sushi_attempt_delete.png
│ ├── sidebar_sushi_management.png
│ ├── sushi_attempt_list.png
│ ├── sushi_button_close.png
│ ├── sushi_button_delete.png
│ ├── sushi_button_save.png
│ ├── sushi_button_save_and_test.png
│ ├── sushi_create_dialog.png
│ ├── sushi_credentials_table.png
│ ├── sushi_edit_dialog.png
│ ├── sushi_test_dialog_start.png
│ ├── sushi_test_failure.png
│ ├── sushi_test_running.png
│ ├── sushi_test_running_cs.png
│ ├── sushi_test_success.png
│ ├── sushi_top_bar.png
│ ├── tag-class-creation-5_0.png
│ ├── tag-creation-5_0.png
│ ├── tag-list-new-tag-5_0.png
│ ├── tag-title-assign-2-5_0.png
│ ├── tag-title-assign-5_0.png
│ ├── tagging-batch-assign-5_0.png
│ ├── tagging-batch-done-5_0.png
│ ├── tagging-batch-example-5_0.png
│ ├── tagging-batch-list-2-5_0.png
│ ├── tagging-batch-list-3-5_0.png
│ ├── tagging-batch-list-5_0.png
│ ├── tagging-batch-preprocess-5_0.png
│ ├── tagging-batch-upload-5_0.png
│ ├── tags-management-empty-5_0.png
│ ├── tags-reporting-filter-5_0.png
│ ├── tags-reporting-grouping-1-5_0.png
│ ├── tags-reporting-grouping-remainder-5_0.png
│ ├── tags-title-filtering-1-5_0.png
│ ├── tags-title-filtering-2-5_0.png
│ └── title-tag-filtering-5_0.png
├── index.rst
├── install.rst
├── requirements.txt
├── server-maintenance.rst
├── tags.rst
├── topics.rst
├── trying-celus.rst
└── user.rst
├── dump_basic_defs.sh
├── fix_csv.py
├── item-report-todo.rst
├── k8s
├── INSTALL.rst
├── celery-beat-deployment.yaml
├── celery-worker-deployment.yaml
├── generate.sh
├── ingress-config.yaml
├── letsencrypt-issuer.yaml
├── nginx-deployment.yaml
├── nginx-ingress.yaml
├── nginx-service.yaml
├── postgres-deployment.yaml
├── postgres-service.yaml
├── redis-deployment.yaml
├── redis-service.yaml
├── secrets
│ ├── secrets-celus.yaml
│ └── secrets-gitlab.yaml
├── web-deployment.yaml
└── web-service.yaml
├── locale
└── cs
│ └── LC_MESSAGES
│ └── django.po
├── manage.py
├── poetry.lock
├── pyproject.toml
├── pytest.ini
├── readthedocs.yaml
├── start_celery.sh
├── start_celerybeat.sh
├── test-data
├── counter4
│ ├── 4_BR2_invalid_location1.xml
│ ├── 4_BR2_not_supported1.xml
│ ├── 4_BR2_service_not_available1.xml
│ ├── 4_BR2_unauthorized1.xml
│ ├── 4_BR2_unauthorized2.xml
│ ├── 4_JR1_missing_reports_tag.xml
│ ├── 4_JR2_denials.tsv
│ ├── 4_PR1_invalid_requestor.xml
│ ├── counter4_br2.tsv
│ ├── counter4_br2_one_month.tsv
│ ├── counter4_jr1_empty.tsv
│ ├── sushi_1111-severity-missing.xml
│ ├── sushi_1111-severity-number.xml
│ ├── sushi_1111.xml
│ ├── sushi_3030.xml
│ ├── sushi_3040.xml
│ └── sushi_exception-with-extra-attrs.xml
├── counter5
│ ├── 5_DR_ProQuestEbookCentral_exception.json
│ ├── 5_TR_ProQuestEbookCentral.json
│ ├── 5_TR_ProQuestEbookCentral_exception.json
│ ├── 5_TR_with_warning.json
│ ├── C5_PR_test.json
│ ├── C5_PR_with_3030.json
│ ├── C5_PR_with_3040.json
│ ├── COUNTER_R5_Report_Examples_DR.csv
│ ├── COUNTER_R5_Report_Examples_PR.csv
│ ├── COUNTER_R5_Report_Examples_TR.csv
│ ├── TR-one-title-more-ids.json
│ ├── TR-wrong-encoding.csv
│ ├── code-zero.json
│ ├── counter5_ir_sample.json
│ ├── counter5_ir_sample.tsv
│ ├── counter5_ir_sample_no_parents.json
│ ├── counter5_table_dr.csv
│ ├── counter5_table_dr.tsv
│ ├── counter5_table_dr_empty.csv
│ ├── counter5_table_ir_m1.csv
│ ├── counter5_table_mismatched_rt.csv
│ ├── counter5_table_pr.csv
│ ├── counter5_table_pr_empty.csv
│ ├── counter5_table_pr_wrong_value.csv
│ ├── counter5_table_tr_empty.csv
│ ├── counter5_tr_nature.json
│ ├── counter5_tr_test1.json
│ ├── counter5_tr_test1_wrong_id.json
│ ├── data_incorrect.json
│ ├── dr-extra-ids.json
│ ├── error-in-root.json
│ ├── invalid-customer.json
│ ├── naked_error.json
│ ├── naked_error_3000.json
│ ├── naked_error_lowercase.json
│ ├── naked_errors.json
│ ├── no_data.json
│ ├── no_data_3050.json
│ ├── no_data_3062.json
│ ├── no_json.txt
│ ├── null-in-Item_ID.json
│ ├── partial_data1.json
│ ├── partial_data2.json
│ ├── partial_data3.json
│ ├── severity-missing.json
│ ├── severity-number.json
│ ├── severity-wrong.json
│ ├── some_data_3050.json
│ ├── some_data_3062.json
│ └── stringified_error.json
├── custom
│ ├── custom_data-2d-3x2x3-endate.csv
│ ├── custom_data-2d-3x2x3-isodate.csv
│ ├── custom_data-2d-3x2x3-org-isodate-single.csv
│ ├── custom_data-2d-3x2x3-org-isodate.csv
│ ├── custom_data-nibbler-simple.csv
│ ├── custom_data-simple-3x3-endate.csv
│ └── custom_data-simple-3x3-isodate.csv
├── releases
│ ├── test_empty_releases.yaml
│ └── test_filled_releases.yaml
└── tagging_batch
│ ├── plain-title-list-with-tags.csv
│ ├── plain-title-list.csv
│ ├── scopus-codes-head.csv
│ ├── scopus-topics-test.csv
│ └── simple-title-list-with-bom.csv
├── test_coverage.sh
├── test_scenarios
├── __init__.py
├── basic.py
└── counter_data.py
└── wsserver.py
/.coveragerc:
--------------------------------------------------------------------------------
1 | [report]
2 | precision = 1
3 | show_missing = true
4 | skip_covered = true
5 |
6 | [run]
7 | omit =
8 | */migrations/*
9 | */management/*
10 | */tests.py
11 | */experiments.py
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | .idea/
3 | *~
4 | config/settings/secret_settings.json
5 | .cache
6 | .coverage
7 | locale/*/LC_MESSAGES/django.mo
8 | celerybeat-schedule
9 | /.pytest_cache
10 | .~*
11 | media/*
12 | /.env
13 | /venv
14 | error.log
15 | .DS_Store
16 |
--------------------------------------------------------------------------------
/.gitlab/pre-commit.yml:
--------------------------------------------------------------------------------
1 | lints:pre_commit:
2 | stage: lints
3 | needs: []
4 | image: registry.gitlab.com/big-dig-data/celus/celus-test:latest
5 | services:
6 | - postgres
7 | variables:
8 | DJANGO_SETTINGS_MODULE: config.settings.test
9 | POSTGRES_DB: celus
10 | POSTGRES_USER: celus
11 | POSTGRES_PASSWORD: celus
12 | POSTGRES_HOST: postgres
13 | before_script:
14 | - poetry install --no-root
15 | - cp .env.example .env
16 | script:
17 | - poetry run pre-commit run --hook-stage push --all-files
18 | tags:
19 | - bdd
20 |
--------------------------------------------------------------------------------
/.gitlab/test-js.yml:
--------------------------------------------------------------------------------
1 | tests:test_js:
2 | stage: tests
3 | needs: []
4 | image: node:18.19
5 | script:
6 | - cd design/ui
7 | - yarn install
8 | - yarn test
9 | tags:
10 | - bdd
11 |
--------------------------------------------------------------------------------
/apps/activity/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/activity/__init__.py
--------------------------------------------------------------------------------
/apps/activity/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import UserActivity
4 |
5 |
6 | @admin.register(UserActivity)
7 | class UserActivityAdmin(admin.ModelAdmin):
8 | list_display = ["user", "timestamp", "action_type"]
9 | list_filter = ["user"]
10 | search_fields = ["user__email", "user__username"]
11 |
--------------------------------------------------------------------------------
/apps/activity/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ActivityConfig(AppConfig):
5 | name = "activity"
6 |
7 | def ready(self):
8 | from . import signals # noqa - this is necessary to run the code in the module
9 |
--------------------------------------------------------------------------------
/apps/activity/migrations/0002_useractivity_plural.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-07-20 17:34
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("activity", "0001_initial")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="useractivity", options={"verbose_name_plural": "User activities"}
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/activity/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/activity/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/activity/models.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.db import models
3 | from django.utils.timezone import now
4 |
5 |
6 | class UserActivity(models.Model):
7 | ACTION_TYPE_LOGIN = "LGN"
8 |
9 | ACTION_TYPE_CHOICES = ((ACTION_TYPE_LOGIN, "Login"),)
10 |
11 | user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
12 | action_type = models.CharField(max_length=3, choices=ACTION_TYPE_CHOICES)
13 | timestamp = models.DateTimeField(default=now)
14 |
15 | class Meta:
16 | verbose_name_plural = "User activities"
17 |
--------------------------------------------------------------------------------
/apps/activity/signals.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth import user_logged_in
2 | from django.dispatch import receiver
3 |
4 | from activity.models import UserActivity
5 |
6 |
7 | @receiver(user_logged_in)
8 | def log_user_activity_login(request, user, **kwargs):
9 | UserActivity.objects.create(user=user, action_type=UserActivity.ACTION_TYPE_LOGIN)
10 |
--------------------------------------------------------------------------------
/apps/activity/tests.py:
--------------------------------------------------------------------------------
1 | # Create your tests here.
2 |
--------------------------------------------------------------------------------
/apps/activity/views.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 |
--------------------------------------------------------------------------------
/apps/annotations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/annotations/__init__.py
--------------------------------------------------------------------------------
/apps/annotations/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from modeltranslation.admin import TranslationAdmin
3 |
4 | from .models import Annotation
5 |
6 |
7 | @admin.register(Annotation)
8 | class AnnotationAdmin(TranslationAdmin):
9 | list_display = [
10 | "subject",
11 | "level",
12 | "start_date",
13 | "end_date",
14 | "organization",
15 | "platform",
16 | "author",
17 | ]
18 | search_fields = [
19 | "subject",
20 | "short_message",
21 | "message",
22 | "organization__short_name",
23 | "platform__short_name",
24 | ]
25 | list_filter = ["level", "platform", "organization", "author"]
26 |
--------------------------------------------------------------------------------
/apps/annotations/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class AnnotationsConfig(AppConfig):
5 | name = "annotations"
6 |
--------------------------------------------------------------------------------
/apps/annotations/migrations/0002_no_title_no_report_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-25 12:23
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("annotations", "0001_initial")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="annotation", name="report_type"),
11 | migrations.RemoveField(model_name="annotation", name="title"),
12 | ]
13 |
--------------------------------------------------------------------------------
/apps/annotations/migrations/0003_annotation_level.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-25 12:28
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("annotations", "0002_no_title_no_report_type")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="annotation",
12 | name="level",
13 | field=models.CharField(
14 | choices=[("info", "info"), ("important", "important")],
15 | default="info",
16 | max_length=20,
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/annotations/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/annotations/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/annotations/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/annotations/tests/__init__.py
--------------------------------------------------------------------------------
/apps/annotations/tests/conftest.py:
--------------------------------------------------------------------------------
1 | from core.tests.conftest import * # noqa - fixtures
2 | from organizations.tests.conftest import * # noqa - fixtures
3 | from publications.tests.conftest import * # noqa - fixtures
4 |
--------------------------------------------------------------------------------
/apps/annotations/translation.py:
--------------------------------------------------------------------------------
1 | from modeltranslation.translator import TranslationOptions, translator
2 |
3 | from .models import Annotation
4 |
5 |
6 | class AnnotationTranslationOptions(TranslationOptions):
7 | fields = ("subject", "short_message", "message")
8 |
9 |
10 | translator.register(Annotation, AnnotationTranslationOptions)
11 |
--------------------------------------------------------------------------------
/apps/annotations/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import DefaultRouter
2 |
3 | from . import views
4 |
5 | router = DefaultRouter()
6 | router.register(r"annotations", views.AnnotationsViewSet, basename="annotations")
7 |
8 | urlpatterns = router.urls
9 |
--------------------------------------------------------------------------------
/apps/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/api/__init__.py
--------------------------------------------------------------------------------
/apps/api/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from rest_framework_api_key.admin import APIKeyModelAdmin
3 |
4 | from api.models import OrganizationAPIKey
5 |
6 |
7 | @admin.register(OrganizationAPIKey)
8 | class OrganizationAPIKeyAdmin(APIKeyModelAdmin):
9 | list_display = [*APIKeyModelAdmin.list_display, "organization"]
10 | search_fields = [*APIKeyModelAdmin.search_fields, "organization__name"]
11 |
--------------------------------------------------------------------------------
/apps/api/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ApiConfig(AppConfig):
5 | name = "api"
6 |
--------------------------------------------------------------------------------
/apps/api/auth.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from organizations.models import Organization
4 | from rest_framework_api_key.permissions import KeyParser
5 |
6 | from api.models import OrganizationAPIKey
7 |
8 |
9 | def extract_org_from_request_api_key(request) -> Optional[Organization]:
10 | key_parser = KeyParser()
11 | key = key_parser.get_from_authorization(request)
12 | if key:
13 | api_key = OrganizationAPIKey.objects.get_from_key(key)
14 | request._api_key = api_key
15 | return api_key.organization
16 | return None
17 |
--------------------------------------------------------------------------------
/apps/api/fake_data.py:
--------------------------------------------------------------------------------
1 | import factory
2 |
3 | from api.models import OrganizationAPIKey
4 |
5 |
6 | class OrganizationAPIKeyFactory(factory.django.DjangoModelFactory):
7 | name = factory.Faker("name")
8 | prefix = factory.Faker("lexify", text="????????")
9 | id = factory.Faker("lexify")
10 |
11 | class Meta:
12 | model = OrganizationAPIKey
13 |
--------------------------------------------------------------------------------
/apps/api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/api/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/api/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from rest_framework_api_key.models import AbstractAPIKey
3 |
4 |
5 | class OrganizationAPIKey(AbstractAPIKey):
6 | organization = models.ForeignKey(
7 | "organizations.Organization", on_delete=models.CASCADE, related_name="api_keys"
8 | )
9 |
--------------------------------------------------------------------------------
/apps/api/permissions.py:
--------------------------------------------------------------------------------
1 | from rest_framework_api_key.permissions import BaseHasAPIKey
2 |
3 | from api.models import OrganizationAPIKey
4 |
5 |
6 | class HasOrganizationAPIKey(BaseHasAPIKey):
7 | model = OrganizationAPIKey
8 |
--------------------------------------------------------------------------------
/apps/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/api/tests/__init__.py
--------------------------------------------------------------------------------
/apps/api/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from logs.tests.conftest import flexible_slicer_test_data, report_type_nd # noqa
3 | from organizations.tests.conftest import organization_random # noqa - used by local tests
4 |
5 | from test_scenarios.basic import * # noqa
6 |
7 |
8 | @pytest.fixture
9 | def root_platform(platforms):
10 | return platforms["root"]
11 |
12 |
13 | @pytest.fixture
14 | def tr_report(report_types):
15 | return report_types["tr"]
16 |
--------------------------------------------------------------------------------
/apps/api/throttling.py:
--------------------------------------------------------------------------------
1 | from core.logic.util import text_hash
2 | from rest_framework.throttling import SimpleRateThrottle
3 |
4 |
5 | class APIKeyBasedThrottle(SimpleRateThrottle):
6 | scope = "remote_api"
7 |
8 | def get_cache_key(self, request, view):
9 | """
10 | Return the cache key for the current request.
11 | We use the value of the `Authorization` header as the key. This way if we give out
12 | multiple API keys to different users for the same organization, they will not interfere.
13 | """
14 | return text_hash(request.headers.get("Authorization", ""))
15 |
--------------------------------------------------------------------------------
/apps/charts/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/charts/__init__.py
--------------------------------------------------------------------------------
/apps/charts/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ChartsConfig(AppConfig):
5 | name = "charts"
6 |
--------------------------------------------------------------------------------
/apps/charts/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/charts/logic/__init__.py
--------------------------------------------------------------------------------
/apps/charts/migrations/0006_chartdefinition_scope.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-12-02 16:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("charts", "0005_chartdefinition_ignore_platform")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="chartdefinition",
12 | name="scope",
13 | field=models.CharField(
14 | choices=[("", "any"), ("platform", "platform"), ("title", "title")],
15 | default="",
16 | max_length=10,
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/charts/migrations/0007_chartdefinition_scope_blank.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.9 on 2020-01-17 13:03
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("charts", "0006_chartdefinition_scope")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="chartdefinition",
12 | name="scope",
13 | field=models.CharField(
14 | blank=True,
15 | choices=[("", "any"), ("platform", "platform"), ("title", "title")],
16 | default="",
17 | max_length=10,
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/charts/migrations/0009_jsonfield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.3 on 2020-11-20 13:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("charts", "0008_datasource_set_null")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="dimensionfilter",
12 | name="allowed_values",
13 | field=models.JSONField(blank=True, default=list),
14 | ),
15 | migrations.AlterField(
16 | model_name="reportdataview",
17 | name="metric_allowed_values",
18 | field=models.JSONField(blank=True, default=list),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/charts/migrations/0011_remove_reportdataview_primary_dimension.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.17 on 2023-02-14 12:27
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("charts", "0010_chartdefinition_is_generic")]
8 |
9 | operations = [migrations.RemoveField(model_name="reportdataview", name="primary_dimension")]
10 |
--------------------------------------------------------------------------------
/apps/charts/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/charts/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/charts/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/charts/tests/__init__.py
--------------------------------------------------------------------------------
/apps/charts/translation.py:
--------------------------------------------------------------------------------
1 | from modeltranslation.translator import TranslationOptions, translator
2 |
3 | from charts.models import ChartDefinition
4 |
5 | from .models import ReportDataView
6 |
7 |
8 | class ReportDataViewTranslationOptions(TranslationOptions):
9 | fields = ("name", "desc")
10 |
11 |
12 | class ChartDefinitionTranslationOptions(TranslationOptions):
13 | fields = ("name", "desc")
14 |
15 |
16 | translator.register(ReportDataView, ReportDataViewTranslationOptions)
17 | translator.register(ChartDefinition, ChartDefinitionTranslationOptions)
18 |
--------------------------------------------------------------------------------
/apps/core/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/__init__.py
--------------------------------------------------------------------------------
/apps/core/admin_site.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.contrib import admin
3 | from django_otp import user_has_device
4 |
5 |
6 | class CelusAdminSite(admin.AdminSite):
7 | def has_permission(self, request):
8 | # Check for OTP in admin only when otp is enabled
9 | # and debug is turned off
10 | if (
11 | settings.OTP_ENABLED
12 | and not settings.DEBUG
13 | and user_has_device(request.user)
14 | and not request.real_user.is_verified()
15 | and not request.real_user.skip_2fa
16 | ):
17 | return False
18 |
19 | return super().has_permission(request)
20 |
--------------------------------------------------------------------------------
/apps/core/authentication.py:
--------------------------------------------------------------------------------
1 | from rest_framework.authentication import SessionAuthentication
2 |
3 |
4 | class SessionAuthentication401(SessionAuthentication):
5 | def authenticate_header(self, request):
6 | return "Session"
7 |
--------------------------------------------------------------------------------
/apps/core/db.py:
--------------------------------------------------------------------------------
1 | from django.db.models import CharField, Lookup, TextField
2 |
3 |
4 | @TextField.register_lookup
5 | @CharField.register_lookup
6 | class ILike(Lookup):
7 | """
8 | Custom lookup that uses ILIKE on Postgres which is much faster than the default approach
9 | when using a TRGM index
10 | """
11 |
12 | lookup_name = "ilike"
13 |
14 | def as_sql(self, compiler, connection):
15 | lhs, lhs_params = self.process_lhs(compiler, connection)
16 | rhs, rhs_params = self.process_rhs(compiler, connection)
17 | params = lhs_params + rhs_params
18 | return f"{lhs} ILIKE CONCAT('%%', {rhs}, '%%')", params
19 |
--------------------------------------------------------------------------------
/apps/core/exceptions.py:
--------------------------------------------------------------------------------
1 | from rest_framework.exceptions import APIException
2 |
3 |
4 | class BadRequestException(APIException):
5 | """
6 | Exception to be used when we need to trigger 400 error response from a view.
7 | """
8 |
9 | status_code = 400
10 | default_code = "bad request"
11 | default_detail = "Incorrect input data for the request"
12 |
13 |
14 | class ModelUsageError(Exception):
15 | """
16 | Used when a model is used in a way that is not allowed or supported.
17 | """
18 |
19 |
20 | class FileConsistencyError(Exception):
21 | """
22 | Used when a file checksum does not match the stored value.
23 | """
24 |
--------------------------------------------------------------------------------
/apps/core/fields.py:
--------------------------------------------------------------------------------
1 | from rest_framework.fields import ListField
2 |
3 |
4 | class CompactListField(ListField):
5 | def get_value(self, dictionary):
6 | if val := dictionary.get(self.field_name):
7 | return val.split(",")
8 | return []
9 |
--------------------------------------------------------------------------------
/apps/core/filters.py:
--------------------------------------------------------------------------------
1 | from rest_framework import filters
2 |
3 |
4 | class PkMultiValueFilterBackend(filters.BaseFilterBackend):
5 | """
6 | Filter that allows selection by a list of primary keys
7 | """
8 |
9 | filter_field = "pk"
10 | query_param = "pks"
11 |
12 | def filter_queryset(self, request, queryset, view):
13 | pks = request.query_params.get(self.query_param)
14 | if pks:
15 | keys = pks.split(",")
16 | queryset = queryset.filter(**{f"{self.filter_field}__in": keys})
17 | return queryset
18 |
--------------------------------------------------------------------------------
/apps/core/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/logic/__init__.py
--------------------------------------------------------------------------------
/apps/core/logic/debug.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | from time import time
4 |
5 | import psutil
6 |
7 |
8 | def memory_usage_psutil():
9 | process = psutil.Process(os.getpid())
10 | mem = process.memory_full_info().rss / float(2**20)
11 | return mem
12 |
13 |
14 | def log_memory(name=""):
15 | usage = memory_usage_psutil()
16 | prefix = f"{name}: " if name else ""
17 | print(f"{prefix}Memory usage: {usage:.2f} MB; time: {time():.3f}", file=sys.stderr)
18 | return usage
19 |
--------------------------------------------------------------------------------
/apps/core/logic/serialization.py:
--------------------------------------------------------------------------------
1 | import json
2 | from base64 import b64decode, b64encode
3 | from typing import Union
4 |
5 |
6 | def b64json(data):
7 | return b64encode(json.dumps(data).encode("utf-8")).decode("ascii")
8 |
9 |
10 | def parse_b64json(data: str) -> Union[dict, list]:
11 | return json.loads(b64decode(data))
12 |
--------------------------------------------------------------------------------
/apps/core/logic/util.py:
--------------------------------------------------------------------------------
1 | from hashlib import blake2b
2 |
3 | from django.conf import settings
4 |
5 |
6 | def text_hash(text: str):
7 | return blake2b(text.encode("utf-8"), digest_size=16).hexdigest()
8 |
9 |
10 | def this_celus_domain():
11 | return settings.ALLOWED_HOSTS[0]
12 |
--------------------------------------------------------------------------------
/apps/core/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/management/__init__.py
--------------------------------------------------------------------------------
/apps/core/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/core/management/commands/sync_maximus.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from core.logic.maximus_sync import sync
4 |
5 |
6 | class Command(BaseCommand):
7 | help = "Sync to celus-maximus"
8 |
9 | def handle(self, *args, **options):
10 | sync()
11 |
--------------------------------------------------------------------------------
/apps/core/migrations/0004_identity_verbosename.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-07-01 16:55
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0003_datasource")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(name="identity", options={"verbose_name_plural": "identities"})
11 | ]
12 |
--------------------------------------------------------------------------------
/apps/core/migrations/0005_user_language.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-05 06:37
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0004_identity_verbosename")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="user",
12 | name="language",
13 | field=models.CharField(
14 | choices=[("en", "English"), ("cs", "Czech")],
15 | default="cs",
16 | help_text="User's preferred language",
17 | max_length=2,
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/core/migrations/0006_blank_ext_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-05 16:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0005_user_language")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="user",
12 | name="ext_id",
13 | field=models.PositiveIntegerField(
14 | blank=True, help_text="ID used in original source of this user data", null=True
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/core/migrations/0008_user_extra_data.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-28 12:52
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("core", "0007_timestamps")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="user",
13 | name="extra_data",
14 | field=django.contrib.postgres.fields.jsonb.JSONField(
15 | default=dict, help_text="User state data that do not deserve a dedicated field"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/core/migrations/0009_user_extra_data_default.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-08-12 17:34
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("core", "0008_user_extra_data")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="user",
13 | name="extra_data",
14 | field=django.contrib.postgres.fields.jsonb.JSONField(
15 | blank=True,
16 | default=dict,
17 | help_text="User state data that do not deserve a dedicated field",
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/core/migrations/0010_default_lang_change.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-09-08 12:07
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0009_user_extra_data_default")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="user",
12 | name="language",
13 | field=models.CharField(
14 | choices=[("en", "English"), ("cs", "Czech")],
15 | default="en",
16 | help_text="User's preferred language",
17 | max_length=2,
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/core/migrations/0013_jsonfield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.3 on 2020-11-20 13:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0012_datasource_set_null")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="user",
12 | name="extra_data",
13 | field=models.JSONField(
14 | blank=True,
15 | default=dict,
16 | help_text="User state data that do not deserve a dedicated field",
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/core/migrations/0014_auto_20210329_1002.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.6 on 2021-03-29 08:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0013_jsonfield")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="user",
12 | name="first_name",
13 | field=models.CharField(blank=True, max_length=150, verbose_name="first name"),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/core/migrations/0016_taskprogress.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-06-23 11:03
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("django_celery_results", "0010_remove_duplicate_indices"),
9 | ("core", "0015_unique_name_within_organization_data_source"),
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name="TaskProgress",
15 | fields=[],
16 | options={"proxy": True, "indexes": [], "constraints": []},
17 | bases=("django_celery_results.taskresult",),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/core/migrations/0018_pgcrypto.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.19 on 2023-06-06 05:42
2 | from django.contrib.postgres.operations import CryptoExtension
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0017_user_extra_data_dismissed_and_seen_last_release")]
8 |
9 | operations = [CryptoExtension()]
10 |
--------------------------------------------------------------------------------
/apps/core/migrations/0019_alter_user_managers.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.19 on 2023-06-27 15:53
2 |
3 | from django.db import migrations
4 |
5 | import core.models
6 |
7 |
8 | class Migration(migrations.Migration):
9 | dependencies = [("core", "0018_pgcrypto")]
10 |
11 | operations = [
12 | migrations.AlterModelManagers(
13 | name="user", managers=[("objects", core.models.CelusUserManager())]
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/core/migrations/0021_user_skip_2fa.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.11 on 2024-04-30 09:22
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("core", "0020_otp_devices")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="user",
12 | name="skip_2fa",
13 | field=models.BooleanField(
14 | default=False, help_text="If set to True, 2FA auth will be bypassed"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/core/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/core/request_logging/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/request_logging/__init__.py
--------------------------------------------------------------------------------
/apps/core/static/__do_not_remove__.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/static/__do_not_remove__.txt
--------------------------------------------------------------------------------
/apps/core/task_support.py:
--------------------------------------------------------------------------------
1 | import logging
2 | from contextlib import contextmanager
3 |
4 | from django.core.cache import cache
5 |
6 | logger = logging.getLogger(__name__)
7 |
8 |
9 | @contextmanager
10 | def cache_based_lock(lock_name, timeout=3600, blocking_timeout=None):
11 | with cache.lock(lock_name, timeout=timeout, blocking_timeout=blocking_timeout):
12 | yield None
13 |
--------------------------------------------------------------------------------
/apps/core/templates/account/email/email_confirmation_message.txt:
--------------------------------------------------------------------------------
1 | {% load account %}{% user_display user as user_display %}{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello,
2 |
3 | you are receiving this email in order to verify your email address for use with Celus.
4 |
5 | To confirm your email, please go to {{ activate_url }}
6 |
7 | If you did not register your email with us, you can safely ignore this email or reply to it to let us know about the situation.
8 |
9 | Have a great day
10 |
11 | The Celus team
12 | {% endblocktrans %}
13 | {% endautoescape %}
14 |
--------------------------------------------------------------------------------
/apps/core/templates/account/email/email_confirmation_signup_message.txt:
--------------------------------------------------------------------------------
1 | {% include 'account/email/email_confirmation_message.txt' %}
2 |
--------------------------------------------------------------------------------
/apps/core/templates/account/email/email_confirmation_signup_subject.txt:
--------------------------------------------------------------------------------
1 | {% include 'account/email/email_confirmation_subject.txt' %}
2 |
--------------------------------------------------------------------------------
/apps/core/templates/account/email/email_confirmation_subject.txt:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% blocktrans %}
3 | Please verify your email address for use with Celus
4 | {% endblocktrans %}
5 |
--------------------------------------------------------------------------------
/apps/core/templates/registration/invitation_email.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% autoescape off %}
2 | {% blocktrans %}You're invited to register into the usage statistics application Celus at {{ site_name }}.{% endblocktrans %}
3 |
4 | {% trans "To accept the invitation, please go to the following page and choose your password:" %}
5 | {% block reset_link %}
6 | {{ protocol }}://{{ domain }}/accept-invitation/?uid={{ uid }}&token={{ token }}
7 | {% endblock %}
8 |
9 | {% trans "Looking forward to meeting you in Celus!" %}
10 |
11 | {% blocktrans %}The Celus team{% endblocktrans %}
12 |
13 | {% endautoescape %}
14 |
--------------------------------------------------------------------------------
/apps/core/templates/registration/invitation_subject.txt:
--------------------------------------------------------------------------------
1 | Celus invitation
2 |
--------------------------------------------------------------------------------
/apps/core/templates/registration/password_reset_message.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}{% autoescape off %}
2 | {% blocktrans %}You're receiving this email because you requested a password reset for your Celus user account at {{ site_name }}.{% endblocktrans %}
3 |
4 | {% trans "Please go to the following page and choose a new password:" %}
5 | {% block reset_link %}
6 | {{ reset_url }}
7 | {% endblock %}
8 | {% trans "Your username, in case you've forgotten:" %} {{ user.email }}
9 |
10 | {% trans "Looking forward to seeing you in Celus again!" %}
11 |
12 | {% blocktrans %}The Celus team{% endblocktrans %}
13 |
14 | {% endautoescape %}
15 |
--------------------------------------------------------------------------------
/apps/core/templates/registration/password_reset_subject.txt:
--------------------------------------------------------------------------------
1 | Celus password reset
2 |
--------------------------------------------------------------------------------
/apps/core/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/core/tests/__init__.py
--------------------------------------------------------------------------------
/apps/core/tests/test_admin.py:
--------------------------------------------------------------------------------
1 | from django.urls import reverse
2 |
3 |
4 | def test_reverse_admin():
5 | # '/custom-admin/' is configured in CELUS_ADMIN_SITE_PATH
6 | # which is set in pytest.ini
7 | assert "/custom-admin/" == reverse("admin:index")
8 |
--------------------------------------------------------------------------------
/apps/cost/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/cost/__init__.py
--------------------------------------------------------------------------------
/apps/cost/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CostConfig(AppConfig):
5 | name = "cost"
6 |
--------------------------------------------------------------------------------
/apps/cost/migrations/0002_payment_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-11-13 08:39
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("organizations", "0013_auto_20191113_0939"),
9 | ("publications", "0014_remove_old_interest_reports_attr"),
10 | ("cost", "0001_initial"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterUniqueTogether(
15 | name="payment", unique_together={("organization", "platform", "year")}
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/cost/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/cost/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/cost/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from .models import Payment
4 |
5 |
6 | class PaymentSerializer(serializers.ModelSerializer):
7 | class Meta:
8 | model = Payment
9 | fields = ["pk", "organization", "platform", "year", "price"]
10 |
--------------------------------------------------------------------------------
/apps/cost/urls.py:
--------------------------------------------------------------------------------
1 | from organizations.urls import router as organization_router
2 | from rest_framework_nested.routers import NestedSimpleRouter
3 |
4 | from . import views
5 |
6 | org_sub_router = NestedSimpleRouter(organization_router, r"organization", lookup="organization")
7 | org_sub_router.register(r"payments", views.OrganizationPaymentViewSet, basename="payments")
8 |
9 | urlpatterns = [] + org_sub_router.urls
10 |
--------------------------------------------------------------------------------
/apps/deployment/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/deployment/__init__.py
--------------------------------------------------------------------------------
/apps/deployment/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from .models import FooterImage, SiteLogo
4 |
5 |
6 | @admin.register(FooterImage)
7 | class FooterImageAdmin(admin.ModelAdmin):
8 | list_display = ("alt_text", "site", "img", "position", "last_modified")
9 | list_display_links = ("alt_text",)
10 |
11 |
12 | @admin.register(SiteLogo)
13 | class SiteLogoAdmin(admin.ModelAdmin):
14 | list_display = ("alt_text", "site", "img", "last_modified")
15 | list_display_links = ("alt_text",)
16 |
--------------------------------------------------------------------------------
/apps/deployment/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class DeploymentConfig(AppConfig):
5 | name = "deployment"
6 |
--------------------------------------------------------------------------------
/apps/deployment/migrations/0002_image_as_filefield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-07-21 14:47
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("deployment", "0001_initial")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="footerimage", name="img", field=models.FileField(upload_to="deployment")
12 | ),
13 | migrations.AlterField(
14 | model_name="sitelogo", name="img", field=models.FileField(upload_to="deployment")
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/apps/deployment/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/deployment/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/deployment/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/deployment/tests/__init__.py
--------------------------------------------------------------------------------
/apps/deployment/tests/test_api.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from core.tests.conftest import site # noqa - fixture
3 | from django.urls import reverse
4 |
5 |
6 | @pytest.mark.django_db
7 | class TestDeploymentAPI:
8 | def test_api_is_open(self, client, site):
9 | resp = client.get(reverse("deployment-overview"))
10 | assert resp.status_code == 200
11 |
--------------------------------------------------------------------------------
/apps/deployment/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from rest_framework.routers import DefaultRouter
3 |
4 | from . import views
5 |
6 | router = DefaultRouter()
7 | router.register(r"footer-image", views.FooterImageViewSet, basename="footer-image")
8 | router.register(r"site-logo", views.SiteLogoViewSet, basename="site-logo")
9 | router.register(r"site", views.SiteViewSet, basename="site")
10 |
11 | urlpatterns = [path("overview/", views.SiteOverview.as_view(), name="deployment-overview")]
12 |
13 | urlpatterns += router.urls
14 |
--------------------------------------------------------------------------------
/apps/erms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/erms/__init__.py
--------------------------------------------------------------------------------
/apps/erms/tests/conftest.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/erms/tests/conftest.py
--------------------------------------------------------------------------------
/apps/events/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/events/__init__.py
--------------------------------------------------------------------------------
/apps/events/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class EventsConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "events"
7 |
8 | def ready(self):
9 | super().ready()
10 | from . import signals # noqa - needed to register the signals
11 |
--------------------------------------------------------------------------------
/apps/events/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/events/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/events/tasks.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | import celery
4 | from core.context_managers import logged_task
5 | from core.logic.error_reporting import email_if_fails
6 |
7 | from events.models import UserEvent
8 |
9 | logger = logging.getLogger(__name__)
10 |
11 |
12 | @celery.shared_task
13 | @logged_task
14 | @email_if_fails
15 | def send_unsent_event_emails_task():
16 | """
17 | Send emails for all unsent events.
18 | """
19 | logger.debug("Sent %d emails", UserEvent.objects.send_emails())
20 |
--------------------------------------------------------------------------------
/apps/events/templates/events/welcome_event_description.md:
--------------------------------------------------------------------------------
1 | Welcome on board.
2 |
3 | For basic information how to get around in Celus, we recommend our knowledge-base https://support.celus.net/support/solutions.
4 |
5 | In case you have any questions, let us know at ask@celus.net. We are happy to help you.
6 |
--------------------------------------------------------------------------------
/apps/events/templates/events/welcome_event_title.txt:
--------------------------------------------------------------------------------
1 | Welcome to Celus
2 |
--------------------------------------------------------------------------------
/apps/events/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/events/tests/__init__.py
--------------------------------------------------------------------------------
/apps/events/tests/conftest.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/events/tests/conftest.py
--------------------------------------------------------------------------------
/apps/events/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import DefaultRouter
2 |
3 | from . import views
4 |
5 | router = DefaultRouter()
6 | router.register(r"user-events", views.UserEventsViewSet, basename="user-events")
7 | router.register(
8 | "user-preferences", views.UserEventPreferencesViewSet, basename="user-event-preferences"
9 | )
10 |
11 | urlpatterns = [*router.urls]
12 |
--------------------------------------------------------------------------------
/apps/export/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/export/__init__.py
--------------------------------------------------------------------------------
/apps/export/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ExportConfig(AppConfig):
5 | name = "export"
6 |
7 | def ready(self):
8 | from . import signals # noqa
9 |
--------------------------------------------------------------------------------
/apps/export/enums.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class FileFormat(models.TextChoices):
5 | XLSX = "XLSX", "XLSX"
6 | XLSX_NO_CHARTS = "XLSX_NO_CHARTS", "XLSX without charts"
7 | ZIP_CSV = "ZIP_CSV", "CSV files inside ZIP archive"
8 |
9 | @classmethod
10 | def file_extension(cls, value):
11 | if value in (cls.XLSX, cls.XLSX_NO_CHARTS):
12 | return "xlsx"
13 | else:
14 | return "zip"
15 |
--------------------------------------------------------------------------------
/apps/export/migrations/0003_created_autoaddnow.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.6 on 2021-04-01 14:25
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("export", "0002_auto_20210329_1002")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="flexibledataexport",
12 | name="created",
13 | field=models.DateTimeField(auto_now_add=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/export/migrations/0004_export_status_error.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-04-20 15:41
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("export", "0003_created_autoaddnow")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="flexibledataexport",
12 | name="status",
13 | field=models.PositiveSmallIntegerField(
14 | choices=[(0, "not started"), (1, "in progress"), (2, "finished"), (3, "error")],
15 | default=0,
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/export/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/export/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/export/signals.py:
--------------------------------------------------------------------------------
1 | from django.db.models.signals import post_delete
2 | from django.dispatch import receiver
3 |
4 | from .models import FlexibleDataExport
5 |
6 |
7 | @receiver(post_delete, sender=FlexibleDataExport)
8 | def delete_export_file_from_direcotry(sender, instance, **kwargs):
9 | instance.output_file.delete(save=False)
10 |
--------------------------------------------------------------------------------
/apps/export/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/export/tests/__init__.py
--------------------------------------------------------------------------------
/apps/export/tests/conftest.py:
--------------------------------------------------------------------------------
1 | from logs.tests.conftest import flexible_slicer_test_data, report_type_nd # noqa - fixtures
2 |
3 | from test_scenarios.basic import users # noqa - fixtures
4 |
--------------------------------------------------------------------------------
/apps/export/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import DefaultRouter
2 |
3 | from . import views
4 |
5 | router = DefaultRouter()
6 | router.register(r"flexible-export", views.FlexibleDataExportViewSet, basename="flexible-export")
7 |
8 | urlpatterns = router.urls
9 |
--------------------------------------------------------------------------------
/apps/impersonate_api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/impersonate_api/__init__.py
--------------------------------------------------------------------------------
/apps/impersonate_api/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ImpersonateApiConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "impersonate_api"
7 |
--------------------------------------------------------------------------------
/apps/impersonate_api/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import SimpleRouter
2 |
3 | from .views import ImpersonateViewSet
4 |
5 | router = SimpleRouter()
6 | router.register("impersonate", ImpersonateViewSet, basename="impersonate")
7 |
8 | urlpatterns = router.urls
9 |
--------------------------------------------------------------------------------
/apps/knowledgebase/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/knowledgebase/__init__.py
--------------------------------------------------------------------------------
/apps/knowledgebase/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class KnowledgebaseConfig(AppConfig):
5 | name = "knowledgebase"
6 |
7 | def ready(self):
8 | from . import signals # noqa
9 |
--------------------------------------------------------------------------------
/apps/knowledgebase/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/knowledgebase/management/__init__.py
--------------------------------------------------------------------------------
/apps/knowledgebase/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/knowledgebase/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/knowledgebase/migrations/0002_jsonfield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.3 on 2020-11-20 13:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("knowledgebase", "0001_initial")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="importattempt", name="stats", field=models.JSONField(blank=True, null=True)
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/knowledgebase/migrations/0006_alter_routersyncattempt_last_error.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.19 on 2023-08-02 13:12
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("knowledgebase", "0005_nibbler")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="routersyncattempt",
12 | name="last_error",
13 | field=models.TextField(blank=True, default=""),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/knowledgebase/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/knowledgebase/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/knowledgebase/templates/knowledgebase/importattempt_changelist.html:
--------------------------------------------------------------------------------
1 | {% extends 'admin/change_list.html' %}
2 |
3 | {% block object-tools %}
4 |
5 |
16 |
17 |
18 | {{ block.super }}
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/apps/logs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/__init__.py
--------------------------------------------------------------------------------
/apps/logs/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class LogsConfig(AppConfig):
5 | name = "logs"
6 |
7 | def ready(self):
8 | super().ready()
9 | from . import signals # noqa - needed to register the signals
10 |
--------------------------------------------------------------------------------
/apps/logs/constants.py:
--------------------------------------------------------------------------------
1 | ACTION_INTEREST_CHANGE = "interest_definition_change"
2 | ACTION_INTEREST_SMART_SYNC = "interest_smart_sync"
3 |
--------------------------------------------------------------------------------
/apps/logs/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/logic/__init__.py
--------------------------------------------------------------------------------
/apps/logs/logic/remap.py:
--------------------------------------------------------------------------------
1 | from ..models import Dimension, DimensionText
2 |
3 |
4 | def remap_dicts(dimension: Dimension, records: [dict], key):
5 | mapping = {
6 | dt.pk: dt.text_local or dt.text for dt in DimensionText.objects.filter(dimension=dimension)
7 | }
8 | for record in records:
9 | record[key] = mapping.get(record.get(key))
10 |
--------------------------------------------------------------------------------
/apps/logs/logic/reporting/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/logic/reporting/__init__.py
--------------------------------------------------------------------------------
/apps/logs/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/management/__init__.py
--------------------------------------------------------------------------------
/apps/logs/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/logs/migrations/0002_add_dimension_sorting.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 14:44
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0001_initial")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="dimension", options={"ordering": ("reporttypetodimension",)}
12 | ),
13 | migrations.AlterModelOptions(
14 | name="reporttypetodimension", options={"ordering": ("position",)}
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0005_metric_active.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-08-06 14:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0004_source_field")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="metric",
12 | name="active",
13 | field=models.BooleanField(
14 | default=True, help_text="Only active metrics are reported to users"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0009_accesslog_import_batch.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-16 07:49
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("logs", "0008_importbatch")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="accesslog",
13 | name="import_batch",
14 | field=models.ForeignKey(
15 | default=None, on_delete=django.db.models.deletion.CASCADE, to="logs.ImportBatch"
16 | ),
17 | preserve_default=False,
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0010_verbose_name_plural.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-16 08:33
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0009_accesslog_import_batch")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="importbatch", options={"verbose_name_plural": "Import batches"}
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0014_default_dimension_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-24 15:50
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0013_nullable_title_mdu_validation")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="dimension",
12 | name="type",
13 | field=models.PositiveSmallIntegerField(
14 | choices=[(1, "integer"), (2, "text")], default=2
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0015_change_data_file_validators.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-29 07:37
2 |
3 | from django.db import migrations, models
4 |
5 | import logs.models
6 |
7 |
8 | class Migration(migrations.Migration):
9 | dependencies = [("logs", "0014_default_dimension_type")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="manualdataupload",
14 | name="data_file",
15 | field=models.FileField(
16 | upload_to=logs.models.where_to_store, validators=[logs.models.validate_mime_type]
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0022_move_some_models_to_charts.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-09-09 08:47
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0021_virtual_report_type_to_report_data_view")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="reportdataview", name="base_report_type"),
11 | migrations.RemoveField(model_name="reportdataview", name="primary_dimension"),
12 | migrations.RemoveField(model_name="reportdataview", name="source"),
13 | migrations.DeleteModel(name="DimensionFilter"),
14 | migrations.DeleteModel(name="ReportDataView"),
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0023_importbatch_interest_processed.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-13 09:26
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0022_move_some_models_to_charts")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="importbatch",
12 | name="interest_processed",
13 | field=models.BooleanField(
14 | default=False, help_text="Was interest already calculated for this import batch"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0024_no_reportinterestmetric_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-09-20 14:09
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0023_importbatch_interest_processed")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="reportinterestmetric", name="name"),
11 | migrations.RemoveField(model_name="reportinterestmetric", name="name_cs"),
12 | migrations.RemoveField(model_name="reportinterestmetric", name="name_en"),
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0027_importbatch_interest_timestamp.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-11-06 09:04
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0026_interest_group_ordering")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="importbatch",
12 | name="interest_timestamp",
13 | field=models.DateTimeField(
14 | blank=True, help_text="When was interest procesed for this batch", null=True
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0041_merge_20210327_1013.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.6 on 2021-03-27 09:13
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("logs", "0040_reporttype_approx_record_count"),
9 | ("logs", "0038_reporttype_materialization_date"),
10 | ]
11 |
12 | operations = []
13 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0050_import_batch_date_remove_import_batch_from_mdu.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.11 on 2022-01-24 13:27
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0049_mdu_many_importbatches")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="manualdataupload", name="import_batch"),
11 | migrations.AddField(
12 | model_name="importbatch", name="date", field=models.DateField(null=True)
13 | ),
14 | ]
15 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0052_remove_importbatch_system_created.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.10 on 2022-02-01 09:04
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0051_split_import_batches")]
8 |
9 | operations = [migrations.RemoveField(model_name="importbatch", name="system_created")]
10 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0055_accesslog_logs_access_platfor_cdb3c4_idx.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-02-17 07:57
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0054_fill_importbatch_date")]
8 |
9 | operations = [
10 | migrations.AddIndex(
11 | model_name="accesslog",
12 | index=models.Index(
13 | fields=["platform", "organization", "report_type"],
14 | name="logs_access_platfor_cdb3c4_idx",
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0056_importbatch_logs_import_date_brin.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-02-23 09:12
2 |
3 | import django.contrib.postgres.indexes
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("logs", "0055_accesslog_logs_access_platfor_cdb3c4_idx")]
9 |
10 | operations = [
11 | migrations.AddIndex(
12 | model_name="importbatch",
13 | index=django.contrib.postgres.indexes.BrinIndex(
14 | fields=["date"], name="logs_import_date_269c60_brin"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0058_manualdataupload_error.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-02-25 22:23
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0057_rename_extra_manualdataupload_preflight")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="manualdataupload",
12 | name="error",
13 | field=models.CharField(blank=True, max_length=50, null=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0061_remove_manualdataupload_is_processed.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-16 13:24
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0060_controlled_metrics")]
8 |
9 | operations = [migrations.RemoveField(model_name="manualdataupload", name="is_processed")]
10 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0062_merge_20220325_1628.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-25 15:28
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("logs", "0057_verbose_names"),
9 | ("logs", "0061_remove_manualdataupload_is_processed"),
10 | ]
11 |
12 | operations = []
13 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0063_alter_reportinterestmetric_interest_group.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-30 06:18
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("logs", "0062_merge_20220325_1628")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="reportinterestmetric",
13 | name="interest_group",
14 | field=models.ForeignKey(
15 | on_delete=django.db.models.deletion.CASCADE, to="logs.interestgroup"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0064_manualdataupload_error_details.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-29 14:30
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0063_alter_reportinterestmetric_interest_group")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="manualdataupload",
12 | name="error_details",
13 | field=models.JSONField(blank=True, null=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0065_remove_dimension_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-14 05:58
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0064_manualdataupload_error_details")]
8 |
9 | operations = [migrations.RemoveField(model_name="dimension", name="type")]
10 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0069_merge_20220603_1325.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-06-03 11:25
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("logs", "0067_alter_importbatchsynclog_state"),
9 | ("logs", "0068_file_checksums"),
10 | ]
11 |
12 | operations = []
13 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0071_mdu_import_batch_ordering.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.15 on 2022-10-21 07:57
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0070_reporttype_ext_id")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="importbatch",
12 | options={"ordering": ("id",), "verbose_name_plural": "Import batches"},
13 | ),
14 | migrations.AlterModelOptions(
15 | name="manualdatauploadimportbatch", options={"ordering": ("mdu_id", "import_batch_id")}
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0073_alter_reportinterestmetric_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.15 on 2022-10-26 13:09
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0072_nibbler")]
8 |
9 | operations = [
10 | migrations.AlterUniqueTogether(
11 | name="reportinterestmetric",
12 | unique_together={("interest_group", "metric", "report_type")},
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0078_remove_organizationplatform_sushi_credentials.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.19 on 2023-07-08 09:48
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0077_remove_source_from_dimension")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="organizationplatform", name="sushi_credentials")
11 | ]
12 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0079_alter_importbatch_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.20 on 2023-08-14 07:18
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("publications", "0037_add_ir_m1_interest_to_all_platforms"),
9 | ("organizations", "0024_alter_userorganization_unique_together"),
10 | ("logs", "0078_remove_organizationplatform_sushi_credentials"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterUniqueTogether(
15 | name="importbatch",
16 | unique_together={("report_type", "organization", "platform", "date")},
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/logs/migrations/0082_importbatch_manual_empty.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.11 on 2024-03-20 11:55
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("logs", "0081_mdu_extra_and_constraints")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="importbatch",
12 | name="manual_empty",
13 | field=models.BooleanField(
14 | default=False, help_text="If the batch was created manually by the user as empty"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/logs/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/logs/static/css/report_type.css:
--------------------------------------------------------------------------------
1 | td.field-record_count {
2 | text-align: right;
3 | }
4 |
--------------------------------------------------------------------------------
/apps/logs/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/logs/tests/__init__.py
--------------------------------------------------------------------------------
/apps/logs/tests/data:
--------------------------------------------------------------------------------
1 | ../../../test-data/
--------------------------------------------------------------------------------
/apps/logs/tests/test_export_utils.py:
--------------------------------------------------------------------------------
1 | from io import StringIO
2 |
3 | from ..logic.export_utils import MappingCSVDictWriter
4 |
5 |
6 | class TestMappingDictWriter:
7 | def test_simple(self):
8 | out = StringIO()
9 | writer = MappingCSVDictWriter(out, fields=[("a", "A"), ("b", "B")])
10 | writer.writerow({"a": 1, "b": 2})
11 | assert out.getvalue().splitlines() == ["A,B", "1,2"]
12 |
--------------------------------------------------------------------------------
/apps/necronomicon/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/necronomicon/__init__.py
--------------------------------------------------------------------------------
/apps/necronomicon/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class NecronomiconConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "necronomicon"
7 |
--------------------------------------------------------------------------------
/apps/necronomicon/fake_data.py:
--------------------------------------------------------------------------------
1 | import factory
2 |
3 | from necronomicon.models import Batch, Candidate
4 |
5 |
6 | class BatchFactory(factory.django.DjangoModelFactory):
7 | class Meta:
8 | model = Batch
9 |
10 |
11 | class CandidateFactory(factory.django.DjangoModelFactory):
12 | batch = factory.SubFactory(Batch)
13 |
14 | class Meta:
15 | model = Candidate
16 |
--------------------------------------------------------------------------------
/apps/necronomicon/migrations/0002_drop_fk_for_task_result.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.17 on 2023-02-15 15:23
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("necronomicon", "0001_initial")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="batch", name="task_result"),
11 | migrations.AddField(
12 | model_name="batch",
13 | name="task_result_id",
14 | field=models.IntegerField(blank=True, null=True),
15 | ),
16 | ]
17 |
--------------------------------------------------------------------------------
/apps/necronomicon/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/necronomicon/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/necronomicon/templates/necronomicon/admin/change_form.html:
--------------------------------------------------------------------------------
1 | {% extends 'admin/change_form.html' %}
2 | {% load i18n %}
3 |
4 | {% block submit_buttons_bottom %}
5 |
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/apps/nibbler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/nibbler/__init__.py
--------------------------------------------------------------------------------
/apps/nibbler/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class NibblerConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "nibbler"
7 |
--------------------------------------------------------------------------------
/apps/nibbler/fake_data.py:
--------------------------------------------------------------------------------
1 | import factory
2 |
3 | from nibbler.models import ParserDefinition
4 |
5 |
6 | class ParserDefinitionFactory(factory.django.DjangoModelFactory):
7 | class Meta:
8 | model = ParserDefinition
9 | django_get_or_create = ("id",)
10 |
11 | report_type_short_name = factory.LazyAttribute(lambda x: x.definition["data_format"]["name"])
12 | short_name = factory.LazyAttribute(lambda x: x.definition["parser_name"])
13 | version = factory.LazyAttribute(lambda x: x.definition["version"])
14 |
--------------------------------------------------------------------------------
/apps/nibbler/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/nibbler/logic/__init__.py
--------------------------------------------------------------------------------
/apps/nibbler/logic/dict_reader.py:
--------------------------------------------------------------------------------
1 | from celus_nibbler.reader import CsvReader, DictReader
2 |
3 |
4 | def get_dict_reader_from_csv(infile, sheet_num: int = 0) -> DictReader:
5 | sheets = CsvReader(infile)
6 | return sheets[sheet_num].dict_reader()
7 |
--------------------------------------------------------------------------------
/apps/nibbler/logic/utils.py:
--------------------------------------------------------------------------------
1 | def all_nibbler_counter_parsers(json_format: bool = False) -> str:
2 | name = "Json" if json_format else "Tabular"
3 | return f"static\\.counter[^\\.]+\\.[^\\.]+.{name}"
4 |
--------------------------------------------------------------------------------
/apps/nibbler/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/nibbler/management/__init__.py
--------------------------------------------------------------------------------
/apps/nibbler/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/nibbler/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/nibbler/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/nibbler/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class OrganizationsConfig(AppConfig):
5 | name = "organizations"
6 |
--------------------------------------------------------------------------------
/apps/organizations/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/logic/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/management/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/management/commands/erms_sync_organizations.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | from django.core.management.base import BaseCommand
4 | from django.db.transaction import atomic
5 |
6 | from ...logic.sync import erms_sync_organizations
7 |
8 | logger = logging.getLogger(__name__)
9 |
10 |
11 | class Command(BaseCommand):
12 | help = "Sync organizations between ERMS and the database"
13 |
14 | def add_arguments(self, parser):
15 | pass
16 |
17 | @atomic
18 | def handle(self, *args, **options):
19 | stats = erms_sync_organizations()
20 | self.stderr.write(self.style.WARNING(f"Import stats: {stats}"))
21 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0003_non_unique_ico.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-26 13:12
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0002_nullable_internal_id")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="organization",
12 | name="ico",
13 | field=models.PositiveIntegerField(help_text="Business registration number"),
14 | ),
15 | migrations.AlterUniqueTogether(name="organization", unique_together={("ico", "level")}),
16 | ]
17 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0008_sushicredentials_enabled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-08-01 16:18
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0007_sushicredentials")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushicredentials", name="enabled", field=models.BooleanField(default=True)
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0010_delete_sushicredentials.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-08-02 08:22
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0009_sushi_credentials_tuning")]
8 |
9 | operations = [migrations.DeleteModel(name="SushiCredentials")]
10 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0013_auto_20191113_0939.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-11-13 08:39
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0012_timestamps")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(name="organization", options={"ordering": ("name",)})
11 | ]
12 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0014_nullable_ico.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.9 on 2020-01-10 10:03
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0013_auto_20191113_0939")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="organization",
12 | name="ico",
13 | field=models.PositiveIntegerField(
14 | blank=True, help_text="Business registration number", null=True
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0015_nullable_ext_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.13 on 2020-06-25 07:56
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0014_nullable_ico")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="organization",
12 | name="ext_id",
13 | field=models.PositiveIntegerField(
14 | default=None, help_text="object ID taken from EMRS", null=True, unique=True
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0019_jsonfield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.3 on 2020-11-20 13:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0018_datasource_set_null")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="organization",
12 | name="address",
13 | field=models.JSONField(blank=True, default=dict),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0021_alter_organization_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-22 14:18
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0020_organization_unique_shortname")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="organization", options={"ordering": ("name",), "verbose_name": "Organization"}
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0022_organization_raw_enabled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.16 on 2022-11-23 13:11
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0021_alter_organization_options")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="organization",
12 | name="raw_data_import_enabled",
13 | field=models.BooleanField(default=False),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0023_alter_organizationaltname_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.18 on 2023-04-11 14:21
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("organizations", "0022_organization_raw_enabled")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(name="organizationaltname", options={"ordering": ["name"]})
11 | ]
12 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/0024_alter_userorganization_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.19 on 2023-05-16 11:10
2 |
3 | from django.conf import settings
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [
9 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
10 | ("organizations", "0023_alter_organizationaltname_options"),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterUniqueTogether(
15 | name="userorganization", unique_together={("user", "organization")}
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/organizations/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/tasks.py:
--------------------------------------------------------------------------------
1 | import celery
2 | from core.context_managers import logged_task
3 | from core.logic.error_reporting import email_if_fails
4 |
5 | from organizations.logic.sync import erms_sync_organizations
6 |
7 |
8 | @celery.shared_task
9 | @logged_task
10 | @email_if_fails
11 | def erms_sync_organizations_task():
12 | erms_sync_organizations()
13 |
--------------------------------------------------------------------------------
/apps/organizations/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/organizations/tests/__init__.py
--------------------------------------------------------------------------------
/apps/organizations/tests/test_db.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from organizations.fake_data import OrganizationFactory
4 |
5 | from ..models import Organization
6 |
7 |
8 | @pytest.mark.django_db
9 | class TestDb:
10 | def test_organization_factory(self):
11 | assert Organization.objects.count() == 0
12 | OrganizationFactory.create()
13 | OrganizationFactory.create()
14 | assert Organization.objects.count() == 2
15 |
16 | def test_organization_str(self):
17 | org = OrganizationFactory.create()
18 | assert str(org) == org.name
19 |
--------------------------------------------------------------------------------
/apps/organizations/translation.py:
--------------------------------------------------------------------------------
1 | from modeltranslation.translator import TranslationOptions, translator
2 |
3 | from .models import Organization
4 |
5 |
6 | class OrganizationTranslationOptions(TranslationOptions):
7 | fields = ("name", "short_name")
8 |
9 |
10 | translator.register(Organization, OrganizationTranslationOptions)
11 |
--------------------------------------------------------------------------------
/apps/organizations/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from rest_framework.routers import DefaultRouter
3 |
4 | from . import views
5 |
6 | router = DefaultRouter()
7 | router.register(r"organization", views.OrganizationViewSet, basename="organization")
8 |
9 | urlpatterns = [
10 | path("run-task/erms-sync-organizations", views.StartERMSSyncOrganizationsTask.as_view())
11 | ]
12 |
13 | urlpatterns += router.urls
14 |
--------------------------------------------------------------------------------
/apps/publications/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/__init__.py
--------------------------------------------------------------------------------
/apps/publications/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class PublicationsConfig(AppConfig):
5 | name = "publications"
6 |
7 | def ready(self):
8 | pass
9 |
--------------------------------------------------------------------------------
/apps/publications/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/logic/__init__.py
--------------------------------------------------------------------------------
/apps/publications/logic/knowledgebase.py:
--------------------------------------------------------------------------------
1 | import typing
2 |
3 |
4 | def get_url(knowledgebase: dict, counter_version: int) -> typing.Optional[str]:
5 | """Returns url from knowledgebase dict"""
6 | try:
7 | providers = [
8 | e for e in knowledgebase["providers"] if e["counter_version"] == counter_version
9 | ]
10 | return providers[0]["provider"]["url"]
11 | except (KeyError, IndexError):
12 | return None
13 |
--------------------------------------------------------------------------------
/apps/publications/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/management/__init__.py
--------------------------------------------------------------------------------
/apps/publications/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/publications/management/commands/erms_sync_platforms.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from django.db.transaction import atomic
3 |
4 | from publications.logic.sync import erms_sync_platforms
5 |
6 |
7 | class Command(BaseCommand):
8 | help = "Sync platforms between ERMS and the database"
9 |
10 | def add_arguments(self, parser):
11 | pass
12 |
13 | @atomic
14 | def handle(self, *args, **options):
15 | stats = erms_sync_platforms()
16 | self.stderr.write(self.style.WARNING(f"Import stats: {stats}"))
17 |
--------------------------------------------------------------------------------
/apps/publications/management/commands/update_arrival_curves.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from django.db.transaction import atomic
3 |
4 | from publications.logic.arrival_probabilities import update_all_arrival_curves
5 |
6 |
7 | class Command(BaseCommand):
8 | help = "Update arrival probabilities for all platforms"
9 |
10 | @atomic
11 | def handle(self, *args, **options):
12 | update_all_arrival_curves()
13 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0002_title_doi.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-24 14:44
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0001_initial")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="title", name="doi", field=models.CharField(blank=True, max_length=250)
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0004_pub_type_verbose_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-06-27 06:05
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0003_nullable_title_attrs")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="title",
12 | name="pub_type",
13 | field=models.CharField(
14 | choices=[("B", "Book"), ("J", "Journal")],
15 | max_length=1,
16 | verbose_name="Publication type",
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0005_auto_20190801_1615.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-08-01 16:15
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0004_pub_type_verbose_name")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(name="title", options={"ordering": ("name", "pub_type")})
11 | ]
12 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0007_title_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-02 15:53
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0006_no_null_title_text_attrs")]
8 |
9 | operations = [
10 | migrations.AlterUniqueTogether(
11 | name="title", unique_together={("name", "isbn", "issn", "eissn", "doi")}
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0010_platform_interest_reports.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-02 07:16
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("logs", "0016_report_interest_metrics"),
9 | ("publications", "0009_even_more_pub_types"),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name="platform",
15 | name="interest_reports",
16 | field=models.ManyToManyField(to="logs.ReportType"),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0011_unlocalize_short_name.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-05 10:30
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0010_platform_interest_reports")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(name="platform", options={"ordering": ("short_name",)}),
11 | migrations.RemoveField(model_name="platform", name="short_name_cs"),
12 | migrations.RemoveField(model_name="platform", name="short_name_en"),
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0014_remove_old_interest_reports_attr.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-10-23 16:54
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0013_platforminterestreport_m2m")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="platform", name="interest_reports"),
11 | migrations.RenameField(
12 | model_name="platform", old_name="interest_reports_through", new_name="interest_reports"
13 | ),
14 | ]
15 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0018_platformtitle_unique_constraint.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.10 on 2020-04-14 13:35
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("organizations", "0014_nullable_ico"),
9 | ("publications", "0017_platformtitle_unique_data"),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterUniqueTogether(
14 | name="platformtitle", unique_together={("title", "platform", "organization", "date")}
15 | )
16 | ]
17 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0020_platform_nullable_ext_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-08-12 17:31
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0019_more_pub_types")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="platform",
12 | name="ext_id",
13 | field=models.PositiveIntegerField(blank=True, null=True, unique=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0023_jsonfield.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.3 on 2020-11-20 13:38
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0022_datasource_set_null")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="platform",
12 | name="knowledgebase",
13 | field=models.JSONField(blank=True, null=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0028_title_uris_proprietary_ids.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-02-24 09:00
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0027_fill_platform_name")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="title", name="proprietary_ids", field=models.JSONField(default=list)
12 | ),
13 | migrations.AddField(model_name="title", name="uris", field=models.JSONField(default=list)),
14 | ]
15 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0028_verbose_names.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-22 14:18
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0027_fill_platform_name")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="platform", options={"ordering": ("short_name",), "verbose_name": "Platform"}
12 | ),
13 | migrations.AlterModelOptions(
14 | name="title",
15 | options={"ordering": ("name", "pub_type"), "verbose_name": "Title/Database"},
16 | ),
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0030_merge_0028_verbose_names_0029_title_default_pub_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-03-25 15:27
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [
8 | ("publications", "0028_verbose_names"),
9 | ("publications", "0029_title_default_pub_type"),
10 | ]
11 |
12 | operations = []
13 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0031_alter_title_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-05 11:19
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0030_merge_0028_verbose_names_0029_title_default_pub_type")]
8 |
9 | operations = [
10 | migrations.AlterUniqueTogether(
11 | name="title",
12 | unique_together={("name", "isbn", "issn", "eissn", "doi", "proprietary_ids")},
13 | )
14 | ]
15 |
--------------------------------------------------------------------------------
/apps/publications/migrations/0040_alter_title_unique_together.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 4.2.11 on 2024-05-27 14:55
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("publications", "0039_alter_titleoverlapbatch_last_updated_by")]
8 |
9 | operations = [migrations.AlterUniqueTogether(name="title", unique_together=set())]
10 |
--------------------------------------------------------------------------------
/apps/publications/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/publications/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/publications/tests/__init__.py
--------------------------------------------------------------------------------
/apps/publications/tests/test_tasks.py:
--------------------------------------------------------------------------------
1 | """
2 | The following tests are not really about the function of the tasks, but rather to make
3 | sure that the tasks do not fail with an error.
4 |
5 | The tasks are not run through celery, but as simple functions
6 | """
7 |
8 | import pytest
9 |
10 | from .. import tasks
11 |
12 |
13 | @pytest.mark.django_db
14 | class TestCeleryTasks:
15 | @pytest.mark.clickhouse
16 | @pytest.mark.django_db(transaction=True)
17 | def test_sync_platform_title_links_task(self, clickhouse_on_off):
18 | tasks.sync_platform_title_links_task()
19 |
20 | def test_merge_titles_task(self):
21 | tasks.merge_titles_task()
22 |
--------------------------------------------------------------------------------
/apps/publications/translation.py:
--------------------------------------------------------------------------------
1 | from modeltranslation.translator import TranslationOptions, translator
2 |
3 | from .models import Platform
4 |
5 |
6 | class PlatformTranslationOptions(TranslationOptions):
7 | fields = ("name", "provider")
8 |
9 |
10 | translator.register(Platform, PlatformTranslationOptions)
11 |
--------------------------------------------------------------------------------
/apps/recache/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/recache/__init__.py
--------------------------------------------------------------------------------
/apps/recache/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class RecacheConfig(AppConfig):
5 | name = "recache"
6 |
--------------------------------------------------------------------------------
/apps/recache/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/recache/management/__init__.py
--------------------------------------------------------------------------------
/apps/recache/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/recache/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/recache/migrations/0003_cachedquery_origin.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-08-24 08:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("recache", "0002_add_stats")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="cachedquery",
12 | name="origin",
13 | field=models.CharField(
14 | blank=True, help_text="Optional identifier of the query's origin", max_length=32
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/recache/migrations/0005_remove_cachedquery_query_pickle.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-08-31 09:09
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("recache", "0004_unique_query_hash")]
8 |
9 | operations = [migrations.RemoveField(model_name="cachedquery", name="query_pickle")]
10 |
--------------------------------------------------------------------------------
/apps/recache/migrations/0006_query_hash_unique_with_django_version.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-09-14 11:50
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("recache", "0005_remove_cachedquery_query_pickle")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="cachedquery",
12 | name="query_hash",
13 | field=models.CharField(help_text="Hash of the query string", max_length=32),
14 | ),
15 | migrations.AlterUniqueTogether(
16 | name="cachedquery", unique_together={("query_hash", "django_version")}
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/recache/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/recache/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/recache/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/recache/tests/__init__.py
--------------------------------------------------------------------------------
/apps/recache/views.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 |
--------------------------------------------------------------------------------
/apps/releases/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/releases/__init__.py
--------------------------------------------------------------------------------
/apps/releases/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ReleasesConfig(AppConfig):
5 | name = "releases"
6 |
--------------------------------------------------------------------------------
/apps/releases/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/releases/logic/__init__.py
--------------------------------------------------------------------------------
/apps/releases/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/releases/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/releases/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/releases/tests/__init__.py
--------------------------------------------------------------------------------
/apps/releases/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from rest_framework.routers import DefaultRouter
3 |
4 | from . import views
5 |
6 | router = DefaultRouter()
7 | router.register(r"releases", views.Releases, basename="releases")
8 |
9 | urlpatterns = [path("changelog/", views.ChangelogAPIView.as_view(), name="changelog")] + router.urls
10 |
--------------------------------------------------------------------------------
/apps/reporting/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | This module is intended for specialized reports which do not fit into the generic reporting
3 | provided in `logs`.
4 | """
5 |
6 | # TODO: remove this comment when the corresponding code from `logs` is moved here.
7 | # It is possible that in the future, we will move some of the code from `logs` to this module.
8 | # It is also possible that a more generic reporting framework will be developed, based on the
9 | # more ad-hoc code in this module.
10 |
--------------------------------------------------------------------------------
/apps/reporting/admin.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/reporting/admin.py
--------------------------------------------------------------------------------
/apps/reporting/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class ReportingConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "reporting"
7 |
--------------------------------------------------------------------------------
/apps/reporting/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/reporting/logic/__init__.py
--------------------------------------------------------------------------------
/apps/reporting/models.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/reporting/models.py
--------------------------------------------------------------------------------
/apps/reporting/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/reporting/tests/__init__.py
--------------------------------------------------------------------------------
/apps/reporting/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | path("reporting/reports/", views.ReportListView.as_view(), name="report-list"),
7 | path(
8 | "reporting/reports//", views.ReportDataView.as_view(), name="report-data"
9 | ),
10 | path(
11 | "reporting/reports//export/",
12 | views.ReportExportView.as_view(),
13 | name="report-export",
14 | ),
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/scheduler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/__init__.py
--------------------------------------------------------------------------------
/apps/scheduler/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class SchedulerConfig(AppConfig):
5 | name = "scheduler"
6 |
7 | def ready(self):
8 | from . import signals # noqa
9 |
--------------------------------------------------------------------------------
/apps/scheduler/filters/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/filters/__init__.py
--------------------------------------------------------------------------------
/apps/scheduler/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/logic/__init__.py
--------------------------------------------------------------------------------
/apps/scheduler/migrations/0005_fetchintention_date_constraint.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.16 on 2020-10-27 15:48
2 |
3 | import django.db.models.expressions
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("scheduler", "0004_automatic")]
9 |
10 | operations = [
11 | migrations.AddConstraint(
12 | model_name="fetchintention",
13 | constraint=models.CheckConstraint(
14 | check=models.Q(start_date__lt=django.db.models.expressions.F("end_date")),
15 | name="timeline",
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/scheduler/migrations/0006_fetchintention_retry_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.16 on 2020-10-30 09:43
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("scheduler", "0005_fetchintention_date_constraint")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="fetchintention",
12 | name="retry_id",
13 | field=models.IntegerField(blank=True, help_text="Identifier of retry queue", null=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/scheduler/migrations/0007_fetchintention_one_to_one_attempt.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.16 on 2020-10-30 12:58
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("scheduler", "0006_fetchintention_retry_id")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="fetchintention",
13 | name="attempt",
14 | field=models.OneToOneField(
15 | null=True,
16 | on_delete=django.db.models.deletion.SET_NULL,
17 | to="sushi.SushiFetchAttempt",
18 | ),
19 | )
20 | ]
21 |
--------------------------------------------------------------------------------
/apps/scheduler/migrations/0010_fetchintention_canceled.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-05-19 08:37
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("scheduler", "0009_rename_retry_id_to_queue_id")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="fetchintention", name="canceled", field=models.BooleanField(default=False)
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/scheduler/migrations/0012_fill_queue_id.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.8 on 2021-10-25 16:08
2 |
3 | from django.db import migrations
4 | from django.db.migrations import RunPython
5 | from django.db.models import F
6 |
7 |
8 | def add_queue_id(apps, schema_editor):
9 | FetchIntention = apps.get_model("scheduler", "FetchIntention")
10 | FetchIntention.objects.filter(queue_id__isnull=True).update(queue_id=F("pk"))
11 | assert FetchIntention.objects.filter(queue_id__isnull=True).count() == 0
12 |
13 |
14 | class Migration(migrations.Migration):
15 | dependencies = [("scheduler", "0011_fetchintention_previous")]
16 |
17 | operations = [RunPython(add_queue_id, RunPython.noop)]
18 |
--------------------------------------------------------------------------------
/apps/scheduler/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/scheduler/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/tests/__init__.py
--------------------------------------------------------------------------------
/apps/scheduler/tests/conftest.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/scheduler/tests/conftest.py
--------------------------------------------------------------------------------
/apps/scheduler/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import SimpleRouter
2 | from rest_framework_nested.routers import NestedSimpleRouter
3 |
4 | from .views import HarvestIntentionViewSet, HarvestViewSet, IntentionViewSet
5 |
6 | router = SimpleRouter()
7 | router.register("harvest", HarvestViewSet, basename="harvest")
8 | router.register("intention", IntentionViewSet, basename="intention")
9 |
10 | harvest_router = NestedSimpleRouter(router, "harvest", lookup="harvest")
11 | harvest_router.register("intention", HarvestIntentionViewSet, basename="harvest-intention")
12 |
13 | urlpatterns = [*router.urls, *harvest_router.urls]
14 |
--------------------------------------------------------------------------------
/apps/sushi/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class SushiConfig(AppConfig):
5 | name = "sushi"
6 |
--------------------------------------------------------------------------------
/apps/sushi/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/logic/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/management/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/migrations/0003_counterreporttype_active.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-02 14:48
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0002_sushifetchattempt")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="counterreporttype",
12 | name="active",
13 | field=models.BooleanField(
14 | default=True,
15 | help_text="When turned off, this type of report will not be automatically "
16 | "downloaded",
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0006_sushicredentials_active_counter_reports.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.1 on 2019-08-08 15:33
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0005_attemp_queuing")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushicredentials",
12 | name="active_counter_reports",
13 | field=models.ManyToManyField(to="sushi.CounterReportType"),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0008_sushiattemp_importbatch_onetoone.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-16 08:33
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("sushi", "0007_sushifetchattempt_import_batch")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="sushifetchattempt",
13 | name="import_batch",
14 | field=models.OneToOneField(
15 | null=True, on_delete=django.db.models.deletion.SET_NULL, to="logs.ImportBatch"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0009_conterreporttype_oneonone_report_type.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-25 07:34
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("sushi", "0008_sushiattemp_importbatch_onetoone")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="counterreporttype",
13 | name="report_type",
14 | field=models.OneToOneField(
15 | on_delete=django.db.models.deletion.CASCADE, to="logs.ReportType"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0011_sushifetchattempt_error_code.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-28 07:24
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0010_counterreporttype_code_choices")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="error_code",
13 | field=models.CharField(blank=True, max_length=12),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0012_sushifetchattempt_contains_data.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-08-28 12:08
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0011_sushifetchattempt_error_code")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="contains_data",
13 | field=models.BooleanField(
14 | default=False, help_text="Does the report actually contain data for import"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0017_sushifetchattempt_processing_info.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.4 on 2019-09-13 08:54
2 |
3 | import django.contrib.postgres.fields.jsonb
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("sushi", "0016_counterreporttype_superseeded_by")]
9 |
10 | operations = [
11 | migrations.AddField(
12 | model_name="sushifetchattempt",
13 | name="processing_info",
14 | field=django.contrib.postgres.fields.jsonb.JSONField(
15 | default=dict, help_text="Internal info"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0018_sushifetchattempt_in_progress.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-09-16 08:52
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0017_sushifetchattempt_processing_info")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="in_progress",
13 | field=models.BooleanField(
14 | default=False, help_text="True if the data is still downloading"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0021_sushifetchattempt_import_crashed.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-09-20 07:52
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0020_remove_JR5_counter_report")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="import_crashed",
13 | field=models.BooleanField(
14 | default=False,
15 | help_text="Set to true if there was an error during data import. Details in log "
16 | "and processing_info",
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0025_remove_counterreporttype_superseeded_by.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-11-06 10:07
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | # dependency on 0028_reporttype_superseeded_by was added ex-post when I found out that
8 | # in some cases the migration order was incorrect and this change occurred before
9 | # 0028_reporttype_superseeded_by which is incorrect
10 | dependencies = [("sushi", "0024_lock_level_change"), ("logs", "0028_reporttype_superseeded_by")]
11 |
12 | operations = [migrations.RemoveField(model_name="counterreporttype", name="superseeded_by")]
13 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0031_sushifetchattempt_last_updated.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.14 on 2020-08-17 09:54
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0030_sushicredentials_title")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="last_updated",
13 | field=models.DateTimeField(auto_now=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0034_longer_data_file_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-09-07 17:38
2 |
3 | from django.db import migrations, models
4 |
5 | import sushi.models
6 |
7 |
8 | class Migration(migrations.Migration):
9 | dependencies = [("sushi", "0033_sushifetchattempt_queue_id")]
10 |
11 | operations = [
12 | migrations.AlterField(
13 | model_name="sushifetchattempt",
14 | name="data_file",
15 | field=models.FileField(
16 | blank=True, max_length=256, null=True, upload_to=sushi.models.where_to_store
17 | ),
18 | )
19 | ]
20 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0035_sushifetchattempt_http_status_code.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.15 on 2020-09-11 14:02
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0034_longer_data_file_field")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="http_status_code",
13 | field=models.PositiveSmallIntegerField(null=True),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0039_remove_http_auth_from_c5.py:
--------------------------------------------------------------------------------
1 | from django.db import migrations
2 |
3 |
4 | def remove_http_auth_from_c5(apps, schema_editor):
5 | SushiCredentials = apps.get_model("sushi", "SushiCredentials")
6 | SushiCredentials.objects.filter(counter_version=5).update(http_password="", http_username="")
7 |
8 |
9 | def noop(apps, schema_editor):
10 | pass
11 |
12 |
13 | class Migration(migrations.Migration):
14 | dependencies = [("sushi", "0038_jsonfield")]
15 |
16 | operations = [migrations.RunPython(remove_http_auth_from_c5, noop)]
17 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0043_sushifetchattempt_partial_data.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.1.8 on 2021-05-11 13:15
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0042_counterreporttype_code_update")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="partial_data",
13 | field=models.BooleanField(default=False, help_text="Data may not be complete"),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0049_sushifetchattempt_extracted_data.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-02-22 16:13
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0048_discard_credentials_broken_state")]
8 |
9 | operations = [
10 | migrations.AddField(
11 | model_name="sushifetchattempt",
12 | name="extracted_data",
13 | field=models.JSONField(
14 | default=dict, help_text="Information extracted from the SUSHI data header"
15 | ),
16 | )
17 | ]
18 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0050_alter_sushicredentials_api_key.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-11 07:50
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0049_sushifetchattempt_extracted_data")]
8 |
9 | operations = [
10 | migrations.AlterField(
11 | model_name="sushicredentials",
12 | name="api_key",
13 | field=models.CharField(blank=True, max_length=400),
14 | )
15 | ]
16 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0051_fetchattempt_remove_queue_stuff.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.12 on 2022-04-27 11:43
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("sushi", "0050_alter_sushicredentials_api_key")]
8 |
9 | operations = [
10 | migrations.RemoveField(model_name="sushifetchattempt", name="queue_id"),
11 | migrations.RemoveField(model_name="sushifetchattempt", name="queue_previous"),
12 | migrations.RemoveField(model_name="sushifetchattempt", name="when_queued"),
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/0056_alter_sushifetchattempt_credentials.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.18 on 2023-05-03 12:32
2 |
3 | import django.db.models.deletion
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 | dependencies = [("sushi", "0055_fill_missing_extracted_data")]
9 |
10 | operations = [
11 | migrations.AlterField(
12 | model_name="sushifetchattempt",
13 | name="credentials",
14 | field=models.ForeignKey(
15 | null=True, on_delete=django.db.models.deletion.SET_NULL, to="sushi.sushicredentials"
16 | ),
17 | )
18 | ]
19 |
--------------------------------------------------------------------------------
/apps/sushi/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/static/admin/admin.css:
--------------------------------------------------------------------------------
1 | #result_list th span,a {white-space: normal;}
2 |
--------------------------------------------------------------------------------
/apps/sushi/tasks.py:
--------------------------------------------------------------------------------
1 | import celery
2 | from core.context_managers import logged_task
3 | from core.logic.error_reporting import email_if_fails
4 |
5 | from sushi.logic.cleanup import delete_fetchattempts_and_related_importbatches
6 |
7 |
8 | @celery.shared_task
9 | @logged_task
10 | @email_if_fails
11 | def delete_fetchattempts_and_related_importbatches_task(fetch_attempts_pks: list):
12 | delete_fetchattempts_and_related_importbatches(fetch_attempts_pks)
13 |
--------------------------------------------------------------------------------
/apps/sushi/templates/Template_for_SushiCredentials_import_consortium.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/templates/Template_for_SushiCredentials_import_consortium.xlsx
--------------------------------------------------------------------------------
/apps/sushi/templates/Template_for_SushiCredentials_import_singleorg.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/templates/Template_for_SushiCredentials_import_singleorg.xlsx
--------------------------------------------------------------------------------
/apps/sushi/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/sushi/tests/__init__.py
--------------------------------------------------------------------------------
/apps/sushi/tests/data:
--------------------------------------------------------------------------------
1 | ../../../test-data/
--------------------------------------------------------------------------------
/apps/sushi/urls.py:
--------------------------------------------------------------------------------
1 | from rest_framework.routers import SimpleRouter
2 |
3 | from . import views
4 |
5 | router = SimpleRouter()
6 | router.register(r"sushi-credentials", views.SushiCredentialsViewSet, basename="sushi-credentials")
7 | router.register(r"counter-report-type", views.CounterReportTypeViewSet)
8 |
9 | urlpatterns = router.urls
10 |
--------------------------------------------------------------------------------
/apps/tags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/__init__.py
--------------------------------------------------------------------------------
/apps/tags/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class TagsConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "tags"
7 |
--------------------------------------------------------------------------------
/apps/tags/filters.py:
--------------------------------------------------------------------------------
1 | from rest_framework import filters
2 |
3 | from tags.models import TagScope
4 |
5 |
6 | class TagClassScopeFilter(filters.BaseFilterBackend):
7 | """
8 | Filter that allows selection of tag scope
9 | """
10 |
11 | filter_field = "scope"
12 | query_param = "scope"
13 |
14 | def filter_queryset(self, request, queryset, view):
15 | scope = request.query_params.get(self.query_param)
16 | if scope and scope in TagScope.values:
17 | queryset = queryset.filter(**{f"{self.filter_field}": scope})
18 | return queryset
19 |
--------------------------------------------------------------------------------
/apps/tags/logic/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/logic/__init__.py
--------------------------------------------------------------------------------
/apps/tags/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/management/__init__.py
--------------------------------------------------------------------------------
/apps/tags/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/management/commands/__init__.py
--------------------------------------------------------------------------------
/apps/tags/migrations/0005_alter_tag_options.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.15 on 2022-08-30 13:38
2 |
3 | from django.db import migrations
4 |
5 |
6 | class Migration(migrations.Migration):
7 | dependencies = [("tags", "0004_alter_taggingbatch_state")]
8 |
9 | operations = [
10 | migrations.AlterModelOptions(
11 | name="tag", options={"ordering": ["name"], "verbose_name": "Tag"}
12 | )
13 | ]
14 |
--------------------------------------------------------------------------------
/apps/tags/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/migrations/__init__.py
--------------------------------------------------------------------------------
/apps/tags/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/apps/tags/tests/__init__.py
--------------------------------------------------------------------------------
/config/__init__.py:
--------------------------------------------------------------------------------
1 | # This will make sure the app is always imported when
2 | # Django starts so that shared_task will use this app.
3 | from .celery_conf import app as celery_app
4 |
5 | __all__ = ["celery_app"]
6 |
--------------------------------------------------------------------------------
/config/celery_conf.py:
--------------------------------------------------------------------------------
1 | from celery import Celery
2 |
3 | app = Celery("celus")
4 |
5 | app.config_from_object("django.conf:settings", namespace="CELERY")
6 |
7 | # Load task modules from all registered Django app configs.
8 | app.autodiscover_tasks()
9 |
10 |
11 | @app.task(bind=True)
12 | def debug_task(self):
13 | print("Request: {0!r}".format(self.request))
14 |
--------------------------------------------------------------------------------
/config/production.wsgi:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.core.wsgi import get_wsgi_application
4 |
5 | os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
6 | os.environ["prometheus_multiproc_dir"] = "/tmp/django_prometheus/"
7 |
8 | application = get_wsgi_application()
9 |
--------------------------------------------------------------------------------
/config/settings/__init__.py:
--------------------------------------------------------------------------------
1 | import re
2 | from pathlib import Path
3 |
4 |
5 | def get_version(base_dir: Path) -> str:
6 | try:
7 | with (base_dir / "pyproject.toml").open() as f:
8 | for line in f.readlines():
9 | match = re.match(r'^version\s+=\s+"([^"]+)"$', line.strip())
10 | if match:
11 | return match.group(1)
12 |
13 | except Exception as e:
14 | raise RuntimeError("Failed to read pyproject.toml") from e
15 |
16 | raise RuntimeError("Version not found in pyproject.toml")
17 |
--------------------------------------------------------------------------------
/config/settings/production.py:
--------------------------------------------------------------------------------
1 | from .base import * # noqa F403 F401
2 |
--------------------------------------------------------------------------------
/config/settings/staging.py:
--------------------------------------------------------------------------------
1 | from .base import * # noqa F403 F401
2 |
3 | ALLOWED_HOSTS = ["stats.test.czechelib.cz"]
4 | LIVE_ERMS_AUTHENTICATION = True
5 |
6 | DEBUG = False
7 |
8 | STATIC_ROOT = "/var/www/celus/static/"
9 | MEDIA_ROOT = "/var/www/celus/media/"
10 |
11 | ADMINS = (("Beda Kosata", "beda@bigdigdata.com"),)
12 |
13 | EMAIL_HOST = "smtp.ntkcz.cz"
14 | SERVER_EMAIL = "admin@stats.test.czechelib.cz"
15 |
--------------------------------------------------------------------------------
/config/staging.wsgi:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | from django.core.wsgi import get_wsgi_application
4 |
5 | os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.staging"
6 | os.environ["prometheus_multiproc_dir"] = "/tmp/django_prometheus/"
7 |
8 | application = get_wsgi_application()
9 |
--------------------------------------------------------------------------------
/config/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for Celus project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/design/ui/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
4 |
--------------------------------------------------------------------------------
/design/ui/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_I18N_LOCALE=en
2 | VUE_APP_I18N_FALLBACK_LOCALE=en
3 |
--------------------------------------------------------------------------------
/design/ui/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/design/ui/README.md:
--------------------------------------------------------------------------------
1 | # ui
2 |
3 | ## Project setup
4 |
5 | ```
6 | yarn install
7 | ```
8 |
9 | ### Compiles and hot-reloads for development
10 |
11 | ```
12 | yarn serve
13 | ```
14 |
15 | ### Compiles and minifies for production
16 |
17 | ```
18 | yarn build
19 | ```
20 |
21 | ### Run your tests
22 |
23 | ```
24 | yarn test
25 | ```
26 |
27 | ### Lints and fixes files
28 |
29 | ```
30 | yarn lint
31 | ```
32 |
33 | ### Customize configuration
34 |
35 | See [Configuration Reference](https://cli.vuejs.org/config/).
36 |
--------------------------------------------------------------------------------
/design/ui/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/app", "@babel/preset-env"],
3 | plugins: ["@babel/plugin-transform-class-properties"],
4 | };
5 |
--------------------------------------------------------------------------------
/design/ui/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/public/favicon.ico
--------------------------------------------------------------------------------
/design/ui/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/public/favicon.png
--------------------------------------------------------------------------------
/design/ui/src/assets/celus-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/celus-dark.png
--------------------------------------------------------------------------------
/design/ui/src/assets/czechelib_logo-mini_color-transp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/czechelib_logo-mini_color-transp.png
--------------------------------------------------------------------------------
/design/ui/src/assets/eu-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/eu-96.png
--------------------------------------------------------------------------------
/design/ui/src/assets/eu-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/eu-large.png
--------------------------------------------------------------------------------
/design/ui/src/assets/eu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/eu.png
--------------------------------------------------------------------------------
/design/ui/src/assets/ex-metric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/ex-metric.png
--------------------------------------------------------------------------------
/design/ui/src/assets/ex-title-metric-publisher-success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/ex-title-metric-publisher-success.png
--------------------------------------------------------------------------------
/design/ui/src/assets/ex-title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/ex-title.png
--------------------------------------------------------------------------------
/design/ui/src/assets/hungry-celus-240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/hungry-celus-240.png
--------------------------------------------------------------------------------
/design/ui/src/assets/hungry-celus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/hungry-celus.png
--------------------------------------------------------------------------------
/design/ui/src/assets/sushi_credentials-enable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/sushi_credentials-enable.png
--------------------------------------------------------------------------------
/design/ui/src/assets/sushi_credentials-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/sushi_credentials-test.png
--------------------------------------------------------------------------------
/design/ui/src/assets/sushi_credentials.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/design/ui/src/assets/sushi_credentials.png
--------------------------------------------------------------------------------
/design/ui/src/components/HoverText.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
33 |
34 |
39 |
--------------------------------------------------------------------------------
/design/ui/src/components/events/EventCategoryMark.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{
7 | $t(`event_category.${item.category}`)
8 | }}
9 |
10 | {{ $t(`event_category_desc.${item.category}`) }}
11 |
12 |
13 |
14 |
26 |
--------------------------------------------------------------------------------
/design/ui/src/components/reporting/MetricChip.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ metric.short_name }}
7 |
8 |
9 |
10 | {{ metric.name || metric.short_name }}
11 |
12 |
13 |
14 |
29 |
--------------------------------------------------------------------------------
/design/ui/src/components/reporting/TrendArrow.vue:
--------------------------------------------------------------------------------
1 |
2 | fa-arrow-{{
8 | diff > 0 || diff === null ? "up" : diff === 0 ? "right" : "down"
9 | }}
10 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/design/ui/src/components/sushi/HarvesterIPAddressList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 | {{ IPv4Address }} (IPv4)
5 |
6 | -
7 | {{ IPv6Address }} (IPv6)
8 |
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/design/ui/src/components/sushi/IconButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
20 |
25 |
--------------------------------------------------------------------------------
/design/ui/src/components/sushi/RegistryIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | fa-registered
7 |
8 |
12 |
13 |
14 |
26 |
--------------------------------------------------------------------------------
/design/ui/src/components/util/DoiLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 | {{ doi }}
9 | fa-external-link-alt
12 |
13 |
14 |
15 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/design/ui/src/components/util/LargeSpinner.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/design/ui/src/components/util/SmallLoader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | far fa-hourglass
4 | fa fa-spinner fa-spin
5 | far fa-check-circle
6 |
7 |
8 |
9 |
19 |
--------------------------------------------------------------------------------
/design/ui/src/libs/charts.js:
--------------------------------------------------------------------------------
1 | export const DEFAULT_VCHARTS_COLORS = [
2 | "#19d4ae",
3 | "#5ab1ef",
4 | "#fa6e86",
5 | "#ffb980",
6 | "#0067a6",
7 | "#c4b4e4",
8 | "#d87a80",
9 | "#9cbbff",
10 | "#d9d0c7",
11 | "#87a997",
12 | "#d49ea2",
13 | "#5b4947",
14 | "#7ba3a8",
15 | ];
16 |
--------------------------------------------------------------------------------
/design/ui/src/libs/db-object-localization.js:
--------------------------------------------------------------------------------
1 | function itemToString(item, locale = "en") {
2 | if (item !== null) {
3 | for (let prefix of ["text_local_", "name_"]) {
4 | let key = `${prefix}${locale}`;
5 | if (item[key]) {
6 | return item[key];
7 | }
8 | }
9 | let result =
10 | item.name || item.short_name || item.text_local_en || item.text;
11 | if (result) {
12 | return result;
13 | }
14 | return (
15 | item.name ?? item.short_name ?? item.text_local_en ?? item.text ?? item
16 | );
17 | }
18 | }
19 |
20 | export { itemToString };
21 |
--------------------------------------------------------------------------------
/design/ui/src/libs/dimensions.js:
--------------------------------------------------------------------------------
1 | const explicitDimensionCount = 8;
2 | const explicitDimensions = [];
3 |
4 | for (let i = 0; i < explicitDimensionCount; i++) {
5 | explicitDimensions.push(`dim${i + 1}`);
6 | }
7 |
8 | export { explicitDimensions, explicitDimensionCount };
9 |
--------------------------------------------------------------------------------
/design/ui/src/libs/email-validation.js:
--------------------------------------------------------------------------------
1 | export default function validateEmail(email) {
2 | const re =
3 | /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
4 | return re.test(String(email).toLowerCase());
5 | }
6 |
--------------------------------------------------------------------------------
/design/ui/src/libs/group-ids.js:
--------------------------------------------------------------------------------
1 | function parseGroupPart(part) {
2 | if (part.match(/^\d+$/)) {
3 | return Number.parseInt(part);
4 | } else if (part === "None") {
5 | return null;
6 | }
7 | return part;
8 | }
9 |
10 | function splitGroup(group) {
11 | if (group.substr(0, 4) === "grp-") {
12 | return group
13 | .substr(4)
14 | .split(/,/)
15 | .map((item) => parseGroupPart(item));
16 | }
17 | }
18 |
19 | export { splitGroup };
20 |
--------------------------------------------------------------------------------
/design/ui/src/libs/interest.js:
--------------------------------------------------------------------------------
1 | function createEmptyInterestRecord() {
2 | return {};
3 | }
4 |
5 | function createLoadingInterestRecord() {
6 | let out = createEmptyInterestRecord();
7 | out["loading"] = true;
8 | return out;
9 | }
10 |
11 | export { createEmptyInterestRecord, createLoadingInterestRecord };
12 |
--------------------------------------------------------------------------------
/design/ui/src/libs/palettes.js:
--------------------------------------------------------------------------------
1 | const echartPalette = [
2 | "#5ab1ef",
3 | "#fa6e86",
4 | "#ffb980",
5 | "#19d4ae",
6 | "#0067a6",
7 | "#c4b4e4",
8 | "#d87a80",
9 | "#9cbbff",
10 | "#d9d0c7",
11 | "#87a997",
12 | ];
13 |
14 | export { echartPalette };
15 |
--------------------------------------------------------------------------------
/design/ui/src/libs/sleep.js:
--------------------------------------------------------------------------------
1 | export default function sleep(ms) {
2 | return new Promise((resolve) => setTimeout(resolve, ms));
3 | }
4 |
--------------------------------------------------------------------------------
/design/ui/src/libs/sources.js:
--------------------------------------------------------------------------------
1 | function badge(item) {
2 | if (item.source && item.source.organization) {
3 | return {
4 | color: "red",
5 | content: "badge.content.organization",
6 | tooltip: "badge.tooltip.organization",
7 | };
8 | }
9 | if (item.counter_registry_id) {
10 | return {
11 | color: "counterRegistry",
12 | content: "badge.content.registry",
13 | tooltip: "badge.tooltip.registry",
14 | };
15 | }
16 | return null;
17 | }
18 |
19 | export { badge };
20 |
--------------------------------------------------------------------------------
/design/ui/src/libs/strings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Generate a pseudo-random string of digits and lower-case letters.
3 | * Math.random().toString(36) produces a string starting with "0.",
4 | * as Math.randow returns a float between 0 * and 1 (excluded).
5 | * Conversion in base 36 produces a string of usually 12 to 13 chars,
6 | * depending on the input.
7 | * @param {number} [length] - Desired length. Max 10-11 characters.
8 | * @returns {string}
9 | */
10 | export function randomString(length = 10) {
11 | return Math.random()
12 | .toString(36)
13 | .substring(2, length + 2);
14 | }
15 |
--------------------------------------------------------------------------------
/design/ui/src/libs/tags.js:
--------------------------------------------------------------------------------
1 | const accessLevels = {
2 | EVERYBODY: 10,
3 | ORG_USERS: 20,
4 | ORG_ADMINS: 30,
5 | CONS_ADMINS: 40,
6 | OWNER: 50,
7 | SYSTEM: 100,
8 | };
9 |
10 | function tagText(tag) {
11 | if (typeof tag === "string") {
12 | return tag;
13 | }
14 | return `${tag.tag_class.name} / ${tag.name}`;
15 | }
16 |
17 | export { accessLevels, tagText };
18 |
--------------------------------------------------------------------------------
/design/ui/src/libs/unique-mapping.js:
--------------------------------------------------------------------------------
1 | export default function uniqueMapping(mapping) {
2 | // mapping is an object with keys and values
3 | // we want to return a new object with the same keys
4 | // but with unique values
5 | // we accomplish this by adding a number to the end of the value
6 | // if the value is used more than once
7 | let idToCount = new Map();
8 | let out = {};
9 | Object.entries(mapping).forEach(([key, value]) => {
10 | let count = idToCount.get(value) || 0;
11 | idToCount.set(value, count + 1);
12 | out[key] = count ? `${value} #${count + 1}` : value;
13 | });
14 | return out;
15 | }
16 |
--------------------------------------------------------------------------------
/design/ui/src/locales/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "message": "hello i18n !!"
3 | }
4 |
--------------------------------------------------------------------------------
/design/ui/src/locales/sources.yaml:
--------------------------------------------------------------------------------
1 | en:
2 | badge:
3 | content:
4 | organization: CUSTOM
5 | registry: Registry
6 | tooltip:
7 | organization: Platform was manually added for this organization only
8 | registry: Platform synchronized with the COUNTER registry
9 |
10 | cs:
11 | badge:
12 | content:
13 | organization: VLASTNÍ
14 | registry: Registry
15 | tooltip:
16 | organization: Platform byla ručně přidána pouze pro tuto organizaci
17 | registry: Platforma synchronizovaná s COUNTER registry
18 |
--------------------------------------------------------------------------------
/design/ui/src/mixins/formRulesMixin.js:
--------------------------------------------------------------------------------
1 | import validateEmail from "@/libs/email-validation";
2 |
3 | export default {
4 | data() {
5 | const minPasswordLength = 8;
6 | return {
7 | minPasswordLength,
8 | rules: {
9 | required: (value) => !!value || this.$t("required"),
10 | min: (v) => v.length >= minPasswordLength || this.$t("min_pwd_length"),
11 | email: (v) => !!validateEmail(v) || this.$t("email_required"),
12 | },
13 | };
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/design/ui/src/pages/FlexiTablePage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/design/ui/src/pages/FlexibleReportsPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/design/ui/src/pages/NotFoundPage.vue:
--------------------------------------------------------------------------------
1 |
2 | en:
3 | title: Sorry, but this page does not exist
4 | note: Maybe one of the options from the menu could be helpful.
5 |
6 | cs:
7 | title: Je nám to líto, ale tato stránka neexistuje
8 | note: Možná Vás zaujme některé z položek v nabídce menu.
9 |
10 |
11 |
12 |
13 | {{ $t("title") }} far fa-frown
14 | {{ $t("note") }}
15 |
16 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/design/ui/src/pages/SushiCredentialsMonthOverviewPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/design/ui/src/pages/TagListPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ $t("pages.tags") }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/design/ui/src/plugins/vuetify.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Vuetify from "vuetify/lib";
3 | import colors from "vuetify/es5/util/colors";
4 |
5 | Vue.use(Vuetify);
6 |
7 | export default new Vuetify({
8 | icons: {
9 | iconfont: "fa",
10 | },
11 | theme: {
12 | themes: {
13 | light: {
14 | primary: "#2d5854",
15 | secondary: colors.teal.lighten2,
16 | accent: colors.orange.lighten2,
17 | counterRegistry: "#107da6",
18 | anchor: "#35827b",
19 | tertiary: "#666666",
20 | },
21 | },
22 | },
23 | });
24 |
--------------------------------------------------------------------------------
/design/ui/src/store/modules/page-settings.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | pageSettings: {},
4 | },
5 |
6 | actions: {
7 | getPageSetting({ state }, { page, key }) {
8 | if (state.pageSettings[page]) {
9 | return state.pageSettings[page][key];
10 | }
11 | },
12 | setPageSetting({ commit }, { page, key, value }) {
13 | commit("setPageSetting", { page, key, value });
14 | },
15 | },
16 |
17 | mutations: {
18 | setPageSetting(state, { page, key, value }) {
19 | if (!state.pageSettings[page]) {
20 | state.pageSettings[page] = {};
21 | }
22 | state.pageSettings[page][key] = value;
23 | },
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/docker/entrypoint-celery-beat.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | celery beat -A config --loglevel=info --pidfile /tmp/celery-beat.pid
4 |
--------------------------------------------------------------------------------
/docker/entrypoint-web.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | wait-for-it -p 5432 -h "${POSTGRES_HOST:-celus-postgres}"
6 | wait-for-it -p 6379 -h "${REDIS_HOST:-celus-redis}"
7 |
8 | python manage.py migrate
9 | python manage.py loaddata data/initial-data.json
10 |
11 | uvicorn --host 0.0.0.0 config.wsgi:application --interface wsgi
12 |
--------------------------------------------------------------------------------
/docker/nginx.conf:
--------------------------------------------------------------------------------
1 | upstream celus {
2 | server web:8000;
3 | }
4 |
5 | server {
6 | listen 80;
7 | root /var/www/celus/static;
8 |
9 | location / {
10 | try_files $uri $uri/ /index.html;
11 | }
12 |
13 | location /api {
14 | proxy_pass http://celus/api;
15 | }
16 |
17 | location /metrics {
18 | proxy_pass http://celus/metrics;
19 | }
20 |
21 | location /wsEc67YNV2sq {
22 | proxy_pass http://celus/wsEc67YNV2sq;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/Uživatelská dokumentace.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/Uživatelská dokumentace.odt
--------------------------------------------------------------------------------
/docs/advanced-topics.rst:
--------------------------------------------------------------------------------
1 | ===============
2 | Advanced topics
3 | ===============
4 |
5 | This part describes more involved and technically demanding features of Celus.
6 |
7 | .. toctree::
8 | :maxdepth: 3
9 | :caption: Contents:
10 |
11 | external-api.rst
12 |
--------------------------------------------------------------------------------
/docs/ansible/celus.yaml:
--------------------------------------------------------------------------------
1 |
2 | - hosts: all
3 | roles:
4 | - {role: celus, tags: ['celus']}
5 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/defaults/main.yml:
--------------------------------------------------------------------------------
1 | # base of git repo path - when project_name is added this path, it should form
2 | # complete path to the project git repo
3 | # should end with /
4 | project_git_path_base: https://github.com/techlib/
5 |
6 | # default branch to check when getting project data from git
7 | project_branch: master
8 |
9 | # default settings version to use
10 | settings_version: production
11 |
12 | settings_dir: config
13 |
14 | # the name of the PostgreSQL database user to make owner of the database
15 | # should match django settings
16 | db_user: "{{ db_name }}"
17 |
18 |
19 | postgres_hba_file: "/var/lib/pgsql/data/pg_hba.conf"
20 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/handlers/main.yaml:
--------------------------------------------------------------------------------
1 | - name: restart apache
2 | service: name=httpd state=reloaded
3 |
4 | - name: reload systemd
5 | systemd: daemon_reload=yes name=celery
6 |
7 | - name: restart celery
8 | service: name=celery state=restarted
9 |
10 | - name: restart celerybeat
11 | service: name=celerybeat state=restarted
12 |
13 | - name: reload postgresql
14 | service: name=postgresql state=reloaded
15 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/etc_confd_celerybeat.j2:
--------------------------------------------------------------------------------
1 | DJANGO_SETTINGS_MODULE={{ settings_dir }}.settings.{{ settings_version }}
2 |
3 | # Absolute or relative path to the 'celery' command:
4 | CELERY_BIN="/opt/virtualenvs/{{ project_name }}/bin/celery"
5 |
6 | # App instance to use
7 | # comment out this line if you don't use an app
8 | CELERY_APP="{{ settings_dir }}"
9 |
10 | # Extra arguments to celerybeat
11 | # disabled on purpose - we do not use django_celery_beat anymore
12 | #CELERYBEAT_OPTS="--scheduler django_celery_beat.schedulers:DatabaseScheduler"
13 |
14 | CELERYD_LOG_LEVEL="info"
15 |
16 | CELERYD_LOG_FILE="/var/log/celery/beat.log"
17 | CELERYD_PID_FILE="/var/run/celery/beat.pid"
18 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/etc_cron_daily_backup_db.j2:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | /bin/su postgres -c "/usr/bin/pg_dump {{ db_name }}" | /usr/bin/zstd -c9 > /root/backup/{{ db_name }}-dump-`date "+%Y%m%d"`.sql.zst
4 | /usr/bin/tar c -I '/usr/bin/zstd -9' -f /root/backup/media-`date "+%Y%m%d"`.tar.zst /var/www/{{ project_name }}/media/
5 |
6 | # delete old backups
7 | /usr/bin/find /root/backup/ -mtime +10 -exec rm {} \;
8 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/etc_cron_daily_cleanup_django_sessions.j2:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DJANGO_SETTINGS_MODULE={{ settings_dir }}.settings.{{ settings_version }} /opt/virtualenvs/{{ project_name }}/bin/python /opt/{{ project_name }}/manage.py clearsessions
4 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/etc_logrotated_celery.j2:
--------------------------------------------------------------------------------
1 | /var/log/celery/*.log {
2 | weekly
3 | missingok
4 | rotate 520
5 | compress
6 | compresscmd /usr/bin/xz
7 | compressext .xz
8 | uncompresscmd /usr/bin/unxz
9 | delaycompress
10 | notifempty
11 | create 0640 celery celery
12 | dateext
13 | dateformat -%Y-%m-%d
14 | }
15 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/etc_profiled_virtualenvwrapper.sh.j2:
--------------------------------------------------------------------------------
1 | export WORKON_HOME=/opt/virtualenvs/
2 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/root_activate_virtualenv.sh.j2:
--------------------------------------------------------------------------------
1 | source /etc/profile.d/virtualenvwrapper.sh
2 | source /usr/local/bin/virtualenvwrapper.sh
3 | export DJANGO_SETTINGS_MODULE={{ settings_dir }}.settings.{{ settings_version }}
4 | workon {{ project_name }}
5 |
--------------------------------------------------------------------------------
/docs/ansible/roles/celus/templates/secret_settings.json.j2:
--------------------------------------------------------------------------------
1 | {
2 | "SECRET_KEY": "{{ django_secret_key }}",
3 | "DB_PASSWORD": "{{ db_password }}",
4 | "ERMS_API_URL": "{{ erms_url }}"
5 | }
6 |
--------------------------------------------------------------------------------
/docs/examples/ex-just-values.csv:
--------------------------------------------------------------------------------
1 | "2019-01","2019-02","2019-03"
2 | 10,20,30
3 |
--------------------------------------------------------------------------------
/docs/examples/ex-just-values.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-just-values.ods
--------------------------------------------------------------------------------
/docs/examples/ex-metric.csv:
--------------------------------------------------------------------------------
1 | "Metric","Jan-2018","Feb-2018","Mar-2018","Apr-2018","May-2018","Jun-2018"
2 | "Exports",1206,24094,24094,24094,24094,24094
3 |
--------------------------------------------------------------------------------
/docs/examples/ex-metric.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-metric.ods
--------------------------------------------------------------------------------
/docs/examples/ex-metric.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-metric.png
--------------------------------------------------------------------------------
/docs/examples/ex-title-metric-publisher-success.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-title-metric-publisher-success.ods
--------------------------------------------------------------------------------
/docs/examples/ex-title-metric-publisher-success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-title-metric-publisher-success.png
--------------------------------------------------------------------------------
/docs/examples/ex-title-metric-publisher.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-title-metric-publisher.ods
--------------------------------------------------------------------------------
/docs/examples/ex-title.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-title.ods
--------------------------------------------------------------------------------
/docs/examples/ex-title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/examples/ex-title.png
--------------------------------------------------------------------------------
/docs/images/api-key-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/api-key-create.png
--------------------------------------------------------------------------------
/docs/images/api-key-get-value.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/api-key-get-value.png
--------------------------------------------------------------------------------
/docs/images/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dashboard.png
--------------------------------------------------------------------------------
/docs/images/dja_add_chart_definition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_chart_definition.png
--------------------------------------------------------------------------------
/docs/images/dja_add_dimension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_dimension.png
--------------------------------------------------------------------------------
/docs/images/dja_add_report_data_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_report_data_view.png
--------------------------------------------------------------------------------
/docs/images/dja_add_report_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_report_type.png
--------------------------------------------------------------------------------
/docs/images/dja_add_report_type_filled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_report_type_filled.png
--------------------------------------------------------------------------------
/docs/images/dja_add_report_view_to_chart_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_add_report_view_to_chart_type.png
--------------------------------------------------------------------------------
/docs/images/dja_report_data_view_tr_jr1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_report_data_view_tr_jr1.png
--------------------------------------------------------------------------------
/docs/images/dja_sushi_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_sushi_app.png
--------------------------------------------------------------------------------
/docs/images/dja_sushi_attempt_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/dja_sushi_attempt_delete.png
--------------------------------------------------------------------------------
/docs/images/sidebar_sushi_management.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sidebar_sushi_management.png
--------------------------------------------------------------------------------
/docs/images/sushi_attempt_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_attempt_list.png
--------------------------------------------------------------------------------
/docs/images/sushi_button_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_button_close.png
--------------------------------------------------------------------------------
/docs/images/sushi_button_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_button_delete.png
--------------------------------------------------------------------------------
/docs/images/sushi_button_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_button_save.png
--------------------------------------------------------------------------------
/docs/images/sushi_button_save_and_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_button_save_and_test.png
--------------------------------------------------------------------------------
/docs/images/sushi_create_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_create_dialog.png
--------------------------------------------------------------------------------
/docs/images/sushi_credentials_table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_credentials_table.png
--------------------------------------------------------------------------------
/docs/images/sushi_edit_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_edit_dialog.png
--------------------------------------------------------------------------------
/docs/images/sushi_test_dialog_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_test_dialog_start.png
--------------------------------------------------------------------------------
/docs/images/sushi_test_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_test_failure.png
--------------------------------------------------------------------------------
/docs/images/sushi_test_running.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_test_running.png
--------------------------------------------------------------------------------
/docs/images/sushi_test_running_cs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_test_running_cs.png
--------------------------------------------------------------------------------
/docs/images/sushi_test_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_test_success.png
--------------------------------------------------------------------------------
/docs/images/sushi_top_bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/sushi_top_bar.png
--------------------------------------------------------------------------------
/docs/images/tag-class-creation-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tag-class-creation-5_0.png
--------------------------------------------------------------------------------
/docs/images/tag-creation-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tag-creation-5_0.png
--------------------------------------------------------------------------------
/docs/images/tag-list-new-tag-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tag-list-new-tag-5_0.png
--------------------------------------------------------------------------------
/docs/images/tag-title-assign-2-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tag-title-assign-2-5_0.png
--------------------------------------------------------------------------------
/docs/images/tag-title-assign-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tag-title-assign-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-assign-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-assign-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-done-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-done-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-example-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-example-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-list-2-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-list-2-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-list-3-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-list-3-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-list-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-list-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-preprocess-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-preprocess-5_0.png
--------------------------------------------------------------------------------
/docs/images/tagging-batch-upload-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tagging-batch-upload-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-management-empty-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-management-empty-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-reporting-filter-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-reporting-filter-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-reporting-grouping-1-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-reporting-grouping-1-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-reporting-grouping-remainder-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-reporting-grouping-remainder-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-title-filtering-1-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-title-filtering-1-5_0.png
--------------------------------------------------------------------------------
/docs/images/tags-title-filtering-2-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/tags-title-filtering-2-5_0.png
--------------------------------------------------------------------------------
/docs/images/title-tag-filtering-5_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/docs/images/title-tag-filtering-5_0.png
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx==2.3.1
2 |
--------------------------------------------------------------------------------
/docs/topics.rst:
--------------------------------------------------------------------------------
1 | =====================
2 | Topical documentation
3 | =====================
4 |
5 | The following documents cover specific topics:
6 |
7 | .. toctree::
8 | :maxdepth: 3
9 | :caption: Contents:
10 |
11 | tags.rst
12 |
--------------------------------------------------------------------------------
/dump_basic_defs.sh:
--------------------------------------------------------------------------------
1 | python manage.py dumpdata --indent=2 sushi.counterreporttype logs.reporttype logs.metric logs.dimension logs.reporttypetodimension logs.dimensiontext
2 |
--------------------------------------------------------------------------------
/k8s/generate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | kompose -f ../docker/docker-compose-k8s.yml convert
4 |
--------------------------------------------------------------------------------
/k8s/ingress-config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: ingress-nginx-controller
5 | namespace: ingress-nginx
6 | data:
7 | use-proxy-protocol: "true"
8 | use-forwarded-headers: "true"
9 |
--------------------------------------------------------------------------------
/k8s/letsencrypt-issuer.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: cert-manager.io/v1alpha2
2 | kind: ClusterIssuer
3 | metadata:
4 | name: letsencrypt
5 | namespace: cert-manager
6 | spec:
7 | acme:
8 | # The ACME server URL
9 | server: https://acme-v02.api.letsencrypt.org/directory
10 | # Email address used for ACME registration
11 | email: root@celus.net
12 | # Name of a secret used to store the ACME account private key
13 | privateKeySecretRef:
14 | name: letsencrypt
15 | # Enable the HTTP-01 challenge provider
16 | solvers:
17 | - http01:
18 | ingress:
19 | class: nginx
20 |
--------------------------------------------------------------------------------
/k8s/nginx-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | annotations:
5 | kompose.cmd: kompose -f ../docker/docker-compose-k8s.yml convert
6 | kompose.version: 1.21.0 (HEAD)
7 | creationTimestamp: null
8 | labels:
9 | io.kompose.service: nginx
10 | name: celus-nginx
11 | spec:
12 | ports:
13 | - name: "80"
14 | port: 80
15 | targetPort: 80
16 | selector:
17 | io.kompose.service: nginx
18 | status:
19 | loadBalancer: {}
20 |
--------------------------------------------------------------------------------
/k8s/postgres-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | annotations:
5 | kompose.cmd: kompose -f ../docker/docker-compose-k8s.yml convert
6 | kompose.version: 1.21.0 (HEAD)
7 | creationTimestamp: null
8 | labels:
9 | io.kompose.service: postgres
10 | name: celus-postgres
11 | spec:
12 | ports:
13 | - name: "5432"
14 | port: 5432
15 | targetPort: 5432
16 | selector:
17 | io.kompose.service: postgres
18 | status:
19 | loadBalancer: {}
20 |
--------------------------------------------------------------------------------
/k8s/redis-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | annotations:
5 | kompose.cmd: kompose -f ../docker/docker-compose-k8s.yml convert
6 | kompose.version: 1.21.0 (HEAD)
7 | creationTimestamp: null
8 | labels:
9 | io.kompose.service: redis
10 | name: celus-redis
11 | spec:
12 | ports:
13 | - name: "6379"
14 | port: 6379
15 | targetPort: 6379
16 | selector:
17 | io.kompose.service: redis
18 | status:
19 | loadBalancer: {}
20 |
--------------------------------------------------------------------------------
/k8s/secrets/secrets-celus.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: celus
5 | type: Opaque
6 | stringData:
7 | DJANGO_SECRET_KEY:
8 | ERMS_API_URL:
9 | POSTGRES_DB:
10 | POSTGRES_USER:
11 | POSTGRES_PASSWORD:
12 | POSTGRES_HOST:
13 | POSTGRES_PORT:
14 | REDIS_HOST:
15 | REDIS_LOCATION:
16 | CELERY_BROKER_URL:
17 |
--------------------------------------------------------------------------------
/k8s/secrets/secrets-gitlab.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: gitlab
5 | type: kubernetes.io/dockerconfigjson
6 | data:
7 | .dockerconfigjson:
8 |
--------------------------------------------------------------------------------
/k8s/web-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | annotations:
5 | kompose.cmd: kompose -f ../docker/docker-compose-k8s.yml convert
6 | kompose.version: 1.21.0 (HEAD)
7 | creationTimestamp: null
8 | labels:
9 | io.kompose.service: web
10 | name: celus-web
11 | spec:
12 | ports:
13 | - name: "8000"
14 | port: 8000
15 | targetPort: 8000
16 | selector:
17 | io.kompose.service: web
18 | status:
19 | loadBalancer: {}
20 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | DJANGO_SETTINGS_MODULE = config.settings.test
3 | python_files = tests.py test_*.py
4 | addopts = --reuse-db --random-order-bucket=global
5 | norecursedirs = design doc pycounter media
6 | markers =
7 | now: marker for tests which are currently developed
8 | clickhouse: uses clickhouse database, automatically create and destroy clickhouse db, enforce single thread
9 | env =
10 | CELUS_ADMIN_SITE_PATH=custom-admin/
11 | CLICKHOUSE_DB=celus_test
12 |
--------------------------------------------------------------------------------
/readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Build documentation in the docs/ directory with Sphinx
9 | sphinx:
10 | configuration: docs/conf.py
11 |
12 | # Optionally build your docs in additional formats such as PDF and ePub
13 | formats: all
14 |
15 | # Optionally set the version of Python and requirements required to build your docs
16 | python:
17 | install:
18 | - requirements: docs/requirements.txt
19 |
--------------------------------------------------------------------------------
/start_celery.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export PYTHONBREAKPOINT=celery.contrib.rdb.set_trace
3 | watchmedo auto-restart -d apps/ -d config/ -p '*.py' -R -- celery -A config worker -Q export,celery,interest,sushi,import,normal,preflight -l DEBUG
4 |
--------------------------------------------------------------------------------
/start_celerybeat.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | watchmedo auto-restart -d apps/ -d config/ -p '*.py' -R -- celery -A config beat -l DEBUG
3 |
--------------------------------------------------------------------------------
/test-data/counter4/4_PR1_invalid_requestor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 2000
5 | Error
6 | Unknown or invalid requestor ID
7 |
8 |
9 |
--------------------------------------------------------------------------------
/test-data/counter4/counter4_jr1_empty.tsv:
--------------------------------------------------------------------------------
1 | Journal Report 1 (R4) Number of Successful Full-Text Article Requests by Month and Journal
2 | Title
3 | 1111111111
4 | Period covered by Report:
5 | 2020-01-01 to 2020-01-31
6 | Date run:
7 | 2020-07-28
8 | Journal Publisher Platform Journal DOI Proprietary Identifier Print ISSN Online ISSN Reporting Period Total Reporting Period HTML Reporting Period PDF Jan-2020
9 |
--------------------------------------------------------------------------------
/test-data/counter5/5_DR_ProQuestEbookCentral_exception.json:
--------------------------------------------------------------------------------
1 | {
2 | "body": null,
3 | "response": {
4 | "number": 1001,
5 | "severity": "Error",
6 | "message": "executeSushiAnalysis"
7 | }
8 | }
--------------------------------------------------------------------------------
/test-data/counter5/TR-wrong-encoding.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/test-data/counter5/TR-wrong-encoding.csv
--------------------------------------------------------------------------------
/test-data/counter5/counter5_table_pr_empty.csv:
--------------------------------------------------------------------------------
1 | Report_Name,Platform Master Report,,,,,,,,,
2 | Report_ID,PR,,,,,,,,,
3 | Release,5,,,,,,,,,
4 | Institution_Name,Sample University,,,,,,,,,
5 | Institution_ID,isni=1234567890,,,,,,,,,
6 | Metric_Types,as selected,,,,,,,,,
7 | Report_Filters,as selected,,,,,,,,,
8 | Report_Attributes,as selected,,,,,,,,,
9 | Exceptions,,,,,,,,,,
10 | Reporting_Period,2017-01-01 to 2017-06-30,,,,,,,,,
11 | Created,2017-05-25,,,,,,,,,
12 | Created_By,Publisher Platform Alpha,,,,,,,,,
13 | ,,,,,,,,,,
14 | Platform,Data_Type,Access_Method,Metric_Type,Reporting_Period_Total,Jan-2017,Feb-2017,Mar-2017,Apr-2017,May-2017,Jun-2017
15 |
--------------------------------------------------------------------------------
/test-data/counter5/data_incorrect.json:
--------------------------------------------------------------------------------
1 | {
2 | "foo": "bar"
3 | }
4 |
--------------------------------------------------------------------------------
/test-data/counter5/error-in-root.json:
--------------------------------------------------------------------------------
1 | {"Report_Header":{"Requestor_ID":"user@example.com","Report_ID":"tr","Customer_ID":"XXXXXXXXXXXXXX","Institution_Name":"National Library","Created_By":"Celus LLC.","Report_Filters":[{"Value":"2019-12","Name":"end_date"},{"Value":"2019-01","Name":"begin_date"},{"Value":"YOP|Access_Method|Access_Type|Data_Type|Section_Type","Name":"attributes_to_show"}]},"Exception":{"Message":"Got response code: 404 for request: https://example.com/path/path","Severity":"Error","Code":2090},"Release":5,"Created":"2020-07-03 02:02:30-0700"}
2 |
--------------------------------------------------------------------------------
/test-data/counter5/invalid-customer.json:
--------------------------------------------------------------------------------
1 | {"Report_Header":{"Requestor_ID":"my.uni","Report_ID":"dr","Customer_ID":"000000000","Created_By":"Celus LLC.","Report_Filters":[{"Value":"2021-12","Name":"end_date"},{"Value":"2021-12","Name":"begin_date"},{"Value":"Access_Method|Data_Type","Name":"attributes_to_show"}]},"Exception":{"Message":"Invalid Customer Id","Severity":"Fatal","Code":1030},"Release":5,"Created":"2022-01-01 00:00:00-0000"}
2 |
--------------------------------------------------------------------------------
/test-data/counter5/naked_error.json:
--------------------------------------------------------------------------------
1 | {
2 | "Code": 1011,
3 | "Severity": "Warning",
4 | "Message": "Report Queued for Processing",
5 | "Help_URL": "https://support.jstor.org",
6 | "Data": "Report is currently queued for processing. Please retry the request after some reasonable time."
7 | }
8 |
--------------------------------------------------------------------------------
/test-data/counter5/naked_error_3000.json:
--------------------------------------------------------------------------------
1 | {
2 | "Code":3000,
3 | "Severity":"Error",
4 | "Message":"Report Not Supported",
5 | "Data":"Unknown report requested: [REPORT-ID]"
6 | }
7 |
--------------------------------------------------------------------------------
/test-data/counter5/naked_error_lowercase.json:
--------------------------------------------------------------------------------
1 | {"number":1001,"severity":"Error","message":"executeSushiAnalysis"}
2 |
--------------------------------------------------------------------------------
/test-data/counter5/naked_errors.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Code": 1011,
4 | "Severity": "Warning",
5 | "Message": "Report Queued for Processing",
6 | "Help_URL": "https://support.jstor.org",
7 | "Data": "Report is currently queued for processing. Please retry the request after some reasonable time."
8 | },
9 | {
10 | "Code": 3060,
11 | "Severity": "Warning",
12 | "Message": "Invalid Report Filter Value",
13 | "Help_URL": "https://support.jstor.org",
14 | "Data": "platform not able to be changed from its value of jstor"
15 | }
16 | ]
17 |
--------------------------------------------------------------------------------
/test-data/counter5/no_data.json:
--------------------------------------------------------------------------------
1 | {"Report_Header":{"Customer_ID":"ffffffff-ffff-ffff-ffff-ffffffffffff","Institution_Name":"My Institution","Institution_ID":[{"Type":"Proprietary","Value":"lyb:DDDDDDDDDDDDDD"}],"Report_Filters":[{"Name":"End_Date","Value":"2018-11-30"},{"Name":"Begin_Date","Value":"2018-11-01"}],"Created":"2020-07-27T07:47:13Z","Created_By":"Celus LLC.","Release":"5","Report_Name":"Title Master Report","Report_ID":"TR"},"Report_Items":[]}
2 |
--------------------------------------------------------------------------------
/test-data/counter5/no_json.txt:
--------------------------------------------------------------------------------
1 | HTTP Error 400: Bad request
2 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-2d-3x2x3-endate.csv:
--------------------------------------------------------------------------------
1 | "Source","Metric","Jan 2019","Feb 2019","Mar 2019"
2 | "Title 1","Metric 1",1,4,7
3 | "Title 1","Metric 2",10,20,30
4 | "Title 2","Metric 1",2,5,8
5 | "Title 2","Metric 2",20,30,40
6 | "Title 3","Metric 1",3,6,9
7 | "Title 3","Metric 2",30,40,50
8 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-2d-3x2x3-isodate.csv:
--------------------------------------------------------------------------------
1 | "Source","Metric","2019-01","2019-02","2019-03"
2 | "Title 1","Metric 1",1,4,7
3 | "Title 1","Metric 2",10,20,30
4 | "Title 2","Metric 1",2,5,8
5 | "Title 2","Metric 2",20,30,40
6 | "Title 3","Metric 1",3,6,9
7 | "Title 3","Metric 2",30,40,50
8 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-2d-3x2x3-org-isodate-single.csv:
--------------------------------------------------------------------------------
1 | "Title","Metric","Organization","2019-01","2019-02","2019-03"
2 | "Title 1","Metric 1","Org1",1,4,7
3 | "Title 1","Metric 2","Org1",10,20,30
4 | "Title 2","Metric 1","Org1",2,5,8
5 | "Title 2","Metric 2","Org1",20,30,40
6 | "Title 3","Metric 1","Org1",3,6,9
7 | "Title 3","Metric 2","Org1",30,40,50
8 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-2d-3x2x3-org-isodate.csv:
--------------------------------------------------------------------------------
1 | "Title","Metric","Organization","2019-01","2019-02","2019-03"
2 | "Title 1","Metric 1","Org1",1,4,7
3 | "Title 1","Metric 2","Org1",10,20,30
4 | "Title 2","Metric 1","Org1",2,5,8
5 | "Title 2","Metric 2","Org1",20,30,40
6 | "Title 3","Metric 1","Org1",3,6,9
7 | "Title 3","Metric 2","Org1",30,40,50
8 | "Title 1","Metric 1","Org2",3,7,10
9 | "Title 1","Metric 2","Org2",11,21,31
10 | "Title 2","Metric 1","Org2",4,7,11
11 | "Title 2","Metric 2","Org2",21,31,41
12 | "Title 3","Metric 1","Org2",5,9,12
13 | "Title 3","Metric 2","Org2",31,41,51
14 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-nibbler-simple.csv:
--------------------------------------------------------------------------------
1 | "Title","2020-01"
2 | "T1","10"
3 | "T2","11"
4 | "T3","12"
5 | "T4","13"
6 | "T5","14"
7 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-simple-3x3-endate.csv:
--------------------------------------------------------------------------------
1 | "Source","Jan 2019","Feb 2019","Mar 2019"
2 | "Title 1",1,4,7
3 | "Title 2",2,5,8
4 | "Title 3",3,6,9
5 |
--------------------------------------------------------------------------------
/test-data/custom/custom_data-simple-3x3-isodate.csv:
--------------------------------------------------------------------------------
1 | "Source","2019-01","2019-02","2019-03"
2 | "Title 1",1,4,7
3 | "Title 2",2,5,8
4 | "Title 3",3,6,9
5 |
--------------------------------------------------------------------------------
/test-data/releases/test_empty_releases.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/test-data/releases/test_empty_releases.yaml
--------------------------------------------------------------------------------
/test-data/tagging_batch/plain-title-list-with-tags.csv:
--------------------------------------------------------------------------------
1 | "Name","ISBN","issn","eISSN","note","tag"
2 | "Foo",9780787960186,,,"isbn13","prase"
3 | "Bar",,"1234-5678",,"issn","hroch"
4 | "Baz",,"9874-6314","2546-5794","both issn and eissn","prase"
5 | "Boo",,"2546-5794",,"eissn already seen","prase"
6 | "Moo",1614294410,,,"isnb10","prase"
7 | "Mar",,,"1234-5678","eissn matching previously seen issn","praze"
8 | "Maz",9781614295365,"2345-6789",,"isbn13 + issn",
9 |
--------------------------------------------------------------------------------
/test-data/tagging_batch/plain-title-list.csv:
--------------------------------------------------------------------------------
1 | Name,ISBN,issn,eISSN,note
2 | Foo,9780787960186,,,isbn13
3 | Bar,,1234-5678,,issn
4 | Baz,,9874-6314,2546-5794,both issn and eissn
5 | Moo,1614294410,,,isnb10
6 | Mar,,,1234-5678,eissn matching previously seen issn
7 | Maz,9781614295365,2345-6789,,isbn13 + issn
8 |
--------------------------------------------------------------------------------
/test-data/tagging_batch/scopus-topics-test.csv:
--------------------------------------------------------------------------------
1 | ISSN,eISSN,Codes
2 | 1234-5678,,1000
3 | 2345-6789,,1101; 1106
4 | ,9999-999X,1107
5 |
--------------------------------------------------------------------------------
/test-data/tagging_batch/simple-title-list-with-bom.csv:
--------------------------------------------------------------------------------
1 | ISSN
2 | 0001-9909
3 | 0306-1078
4 | 0013-7227
5 | 0013-8215
6 | 0014-0856
7 | 0022-2097
8 | 0146-8693
9 | 0002-7189
10 | 0007-5027
11 | 0195-6167
12 | 0027-4631
13 | 0036-9543
14 | 0037-3222
15 | 0084-4144
16 |
--------------------------------------------------------------------------------
/test_coverage.sh:
--------------------------------------------------------------------------------
1 | DJANGO_SETTINGS_MODULE=config.settings.devel pytest --cov=publications --cov=core --cov=logs --cov=erms --cov=organizations --cov=sushi
2 |
--------------------------------------------------------------------------------
/test_scenarios/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlib/celus/5ad1bd73a210cb5456eeea442913fa4f7649b7b5/test_scenarios/__init__.py
--------------------------------------------------------------------------------