From 4079ea05a8eed915ad74143a43c7be665b70e6a8 Mon Sep 17 00:00:00 2001 From: RuthShryock Date: Thu, 14 Nov 2024 16:22:09 -0500 Subject: [PATCH] revert to before Submissions name change --- .github/CODEOWNERS | 45 +- README.md | 4 +- dependencies/pip/dev_requirements.txt | 4 +- dependencies/pip/requirements.in | 2 +- dependencies/pip/requirements.txt | 4 +- hub/admin/extend_user.py | 43 +- hub/models/extra_user_detail.py | 5 +- hub/static/admin/css/inline_as_fieldset.css | 3 + jsapp/js/account/accountSidebar.tsx | 18 +- .../account/add-ons/addOnList.component.tsx | 323 ++++---- .../js/account/add-ons/addOnList.module.scss | 117 ++- .../add-ons/oneTimeAddOnRow.component.tsx | 205 +++++ .../add-ons/updateBadge.component..tsx | 62 ++ .../billingContextProvider.component.tsx | 7 +- .../requireOrgOwner.component.tsx | 33 - .../account/plans/billingButton.module.scss | 1 + .../account/plans/planContainer.component.tsx | 8 +- .../js/account/plans/useDisplayPrice.hook.tsx | 6 + jsapp/js/account/routes.tsx | 57 +- jsapp/js/account/stripe.api.ts | 73 +- jsapp/js/account/stripe.types.ts | 34 +- jsapp/js/account/stripe.utils.ts | 52 +- .../oneTimeAddOnList.component.tsx | 69 ++ .../oneTimeAddOnList.module.scss | 21 + .../oneTimeAddOnUsageModal.component.tsx | 105 +++ .../oneTimeAddOnUsageModal.module.scss | 57 ++ jsapp/js/account/usage/usage.component.tsx | 151 +++- jsapp/js/account/usage/usageContainer.tsx | 178 ++--- jsapp/js/account/useOneTimeAddonList.hook.ts | 37 + jsapp/js/api.endpoints.ts | 1 + jsapp/js/components/common/button.scss | 3 +- .../header/mainHeader.component.tsx | 7 +- .../components/header/mainHeader.module.scss | 6 + .../header/organizationBadge.module.scss | 1 - jsapp/js/components/modals/koboModal.scss | 1 - ...rojectOwnershipTransferModalWithBanner.tsx | 75 ++ .../projectTransferInviteBanner.module.scss | 19 + .../projectTransferInviteBanner.tsx | 64 ++ .../special/koboAccessibleSelect.module.scss | 16 +- .../special/koboAccessibleSelect.tsx | 105 ++- .../usageLimits/useExceedingLimits.hook.ts | 30 +- jsapp/js/constants.ts | 2 +- jsapp/js/dataInterface.ts | 6 +- jsapp/js/envStore.ts | 6 +- jsapp/js/featureFlags.ts | 3 +- jsapp/js/projects/customViewRoute.tsx | 162 +--- jsapp/js/projects/customViewStore.ts | 18 +- jsapp/js/projects/myProjectsRoute.module.scss | 39 - jsapp/js/projects/myProjectsRoute.tsx | 247 +----- jsapp/js/projects/projectViews.module.scss | 43 +- jsapp/js/projects/projectViews/constants.ts | 2 + .../projectViews/projectsFieldsSelector.tsx | 9 +- .../projectViews/projectsFilter.module.scss | 4 + .../projects/projectViews/projectsFilter.tsx | 11 +- .../projectViews/projectsFilterEditor.tsx | 13 +- .../js/projects/projectViews/viewSwitcher.tsx | 29 +- .../bulkActions/bulkDeletePrompt.tsx | 13 +- .../projectsTable/projectBulkActions.tsx | 13 +- .../projectsTable/projectQuickActions.tsx | 19 +- .../projects/projectsTable/projectsTable.tsx | 15 +- .../projectsTable/projectsTableHeader.tsx | 15 +- .../projectsTableRow.module.scss | 1 + .../projectsTable/projectsTableRow.tsx | 29 +- .../sortableProjectColumnHeader.tsx | 14 +- jsapp/js/projects/universalProjectsRoute.tsx | 205 +++++ .../validateOrgPermissions.component.tsx | 46 ++ ...paginatedQueryUniversalTable.component.tsx | 2 +- kobo/apps/audit_log/audit_actions.py | 10 + kobo/apps/audit_log/base_views.py | 26 +- kobo/apps/audit_log/models.py | 142 +++- kobo/apps/audit_log/signals.py | 12 +- kobo/apps/audit_log/tests/test_models.py | 213 +++++- .../tests/test_project_history_logs.py | 512 ++++++++++++- kobo/apps/hook/tests/hook_test_case.py | 126 +--- kobo/apps/hook/utils/tests/__init__.py | 0 kobo/apps/hook/utils/tests/mixins.py | 119 +++ kobo/apps/hook/views/v2/hook.py | 12 +- kobo/apps/kobo_auth/models.py | 14 +- .../tests/fixtures/Transportation Form.xml | 326 ++++---- .../viewsets/test_xform_submission_api.py | 6 +- .../api/tests/viewsets/test_xform_viewset.py | 1 + .../apps/api/viewsets/xform_submission_api.py | 9 +- .../commands/populate_submission_counters.py | 21 +- .../update_attachment_storage_bytes.py | 19 +- ..._populate_daily_xform_counters_for_year.py | 34 +- .../0030_backfill_lost_monthly_counters.py | 68 -- .../0031_remove_null_user_daily_counters.py | 10 - ...032_alter_daily_submission_counter_user.py | 2 +- .../0038_add_mongo_uuid_field_to_xform.py | 22 + .../migrations/0039_populate_counters.py | 120 +++ .../openrosa/apps/logger/models/instance.py | 7 +- .../apps/openrosa/apps/logger/models/xform.py | 74 +- .../0017_userprofile_submissions_suspended.py | 18 + .../openrosa/apps/main/models/user_profile.py | 1 + .../apps/openrosa/apps/main/service_health.py | 49 -- .../transportation/transportation.xml | 329 ++++---- kobo/apps/openrosa/apps/main/urls.py | 259 ++++--- .../apps/viewer/models/data_dictionary.py | 4 +- .../apps/viewer/models/parsed_instance.py | 13 +- kobo/apps/openrosa/libs/filters.py | 56 +- kobo/apps/openrosa/libs/utils/logger_tools.py | 4 +- kobo/apps/organizations/admin.py | 64 -- kobo/apps/organizations/admin/__init__.py | 7 + kobo/apps/organizations/admin/organization.py | 90 +++ .../admin/organization_invite.py | 8 + .../organizations/admin/organization_owner.py | 24 + .../organizations/admin/organization_user.py | 156 ++++ kobo/apps/organizations/constants.py | 8 +- kobo/apps/organizations/exceptions.py | 2 + kobo/apps/organizations/forms.py | 24 + .../0006_update_organization_name.py | 10 +- kobo/apps/organizations/models.py | 147 +++- kobo/apps/organizations/permissions.py | 28 +- kobo/apps/organizations/serializers.py | 7 +- kobo/apps/organizations/tasks.py | 30 + ..._organization.py => test_organizations.py} | 27 +- .../tests/test_organizations_api.py | 711 +++++++++++++++++- .../tests/test_organizations_model.py | 22 + kobo/apps/organizations/types.py | 3 + kobo/apps/organizations/utils.py | 29 +- kobo/apps/organizations/views.py | 83 +- .../0003_create_proxy_and_add_invite_type.py | 53 ++ kobo/apps/project_ownership/models/invite.py | 153 +++- .../apps/project_ownership/models/transfer.py | 30 +- .../project_ownership/serializers/invite.py | 151 +--- .../tests/api/v2/test_api.py | 68 +- kobo/apps/project_ownership/utils.py | 77 +- .../service_health/test_service_health.py | 10 - kobo/apps/service_health/views.py | 36 +- kobo/apps/stripe/admin.py | 59 ++ kobo/apps/stripe/constants.py | 11 + kobo/apps/stripe/migrations/0001_initial.py | 102 +++ kobo/apps/stripe/migrations/__init__.py | 0 kobo/apps/stripe/models.py | 254 +++++++ kobo/apps/stripe/serializers.py | 21 +- .../templates/admin/add-ons/change_list.html | 8 + .../stripe/tests/test_customer_portal_api.py | 18 +- .../stripe/tests/test_one_time_addons_api.py | 188 ++++- .../stripe/tests/test_organization_usage.py | 53 +- .../stripe/tests/test_subscription_api.py | 4 +- kobo/apps/stripe/utils.py | 90 ++- kobo/apps/stripe/views.py | 62 +- .../integrations/google/google_transcribe.py | 2 + .../tests/test_submission_extras_api_post.py | 15 +- kobo/apps/trackers/tests/test_utils.py | 121 +++ kobo/apps/trackers/utils.py | 69 +- kobo/apps/trash_bin/utils.py | 4 +- kobo/settings/base.py | 10 + kpi/backends.py | 7 +- kpi/db_routers.py | 9 +- kpi/deployment_backends/openrosa_backend.py | 35 +- kpi/filters.py | 40 +- kpi/fixtures/asset_with_settings_and_qa.json | 10 +- kpi/fixtures/conflicting_versions.json | 71 +- ...ove_projectviewexporttask_data_and_more.py | 76 +- ...nousexport_submissionssynchronousexport.py | 19 + ...rename_exporttask_submissionsexporttask.py | 19 + kpi/mixins/object_permission.py | 58 +- kpi/models/__init__.py | 6 +- kpi/models/asset_file.py | 18 +- kpi/models/import_export_task.py | 65 +- kpi/models/paired_data.py | 4 + kpi/paginators.py | 2 +- kpi/permissions.py | 31 +- kpi/serializers/v1/export_task.py | 6 +- kpi/serializers/v2/asset.py | 29 +- kpi/serializers/v2/export_task.py | 11 +- kpi/serializers/v2/service_usage.py | 4 + kpi/tasks.py | 5 +- kpi/tests/api/test_api_environment.py | 30 +- kpi/tests/api/v1/test_api_assets.py | 10 +- kpi/tests/api/v1/test_api_exports.py | 8 +- .../test_api_asset_permission_assignment.py | 3 +- kpi/tests/api/v2/test_api_assets.py | 125 +-- kpi/tests/api/v2/test_api_collections.py | 83 +- kpi/tests/api/v2/test_api_exports.py | 4 +- kpi/tests/api/v2/test_api_imports.py | 88 ++- kpi/tests/api/v2/test_api_permissions.py | 15 +- kpi/tests/api/v2/test_api_service_usage.py | 8 +- kpi/tests/api/v2/test_api_submissions.py | 172 +---- kpi/tests/base_test_case.py | 87 ++- kpi/tests/kpi_test_case.py | 55 -- kpi/tests/test_asset_snapshots.py | 2 +- kpi/tests/test_cache_utils.py | 55 ++ ...t_mock_data_conflicting_version_exports.py | 9 +- kpi/tests/test_mock_data_exports.py | 48 +- kpi/tests/test_organization.py | 49 -- kpi/tests/test_permissions.py | 48 +- kpi/tests/test_usage_calculator.py | 42 +- kpi/tests/utils/mixins.py | 336 +++++++++ kpi/utils/cache.py | 106 ++- kpi/utils/data_exports.py | 14 +- kpi/utils/django_orm_helper.py | 32 +- kpi/utils/project_views.py | 2 + kpi/utils/pyxform_compatibility.py | 38 + kpi/utils/usage_calculator.py | 66 +- kpi/views/environment.py | 3 +- kpi/views/v1/export_task.py | 30 +- kpi/views/v1/import_task.py | 6 + kpi/views/v2/asset.py | 58 +- kpi/views/v2/asset_export_settings.py | 4 +- kpi/views/v2/asset_file.py | 24 +- kpi/views/v2/asset_snapshot.py | 66 +- kpi/views/v2/export_task.py | 11 +- kpi/views/v2/import_task.py | 12 +- kpi/views/v2/paired_data.py | 19 +- pip-compile.sh | 6 +- 207 files changed, 8031 insertions(+), 3073 deletions(-) create mode 100644 hub/static/admin/css/inline_as_fieldset.css create mode 100644 jsapp/js/account/add-ons/oneTimeAddOnRow.component.tsx create mode 100644 jsapp/js/account/add-ons/updateBadge.component..tsx delete mode 100644 jsapp/js/account/organizations/requireOrgOwner.component.tsx create mode 100644 jsapp/js/account/usage/one-time-add-on-usage-modal/one-time-add-on-list/oneTimeAddOnList.component.tsx create mode 100644 jsapp/js/account/usage/one-time-add-on-usage-modal/one-time-add-on-list/oneTimeAddOnList.module.scss create mode 100644 jsapp/js/account/usage/one-time-add-on-usage-modal/oneTimeAddOnUsageModal.component.tsx create mode 100644 jsapp/js/account/usage/one-time-add-on-usage-modal/oneTimeAddOnUsageModal.module.scss create mode 100644 jsapp/js/account/useOneTimeAddonList.hook.ts create mode 100644 jsapp/js/components/permissions/transferProjects/projectOwnershipTransferModalWithBanner.tsx create mode 100644 jsapp/js/components/permissions/transferProjects/projectTransferInviteBanner.module.scss create mode 100644 jsapp/js/components/permissions/transferProjects/projectTransferInviteBanner.tsx delete mode 100644 jsapp/js/projects/myProjectsRoute.module.scss create mode 100644 jsapp/js/projects/universalProjectsRoute.tsx create mode 100644 jsapp/js/router/validateOrgPermissions.component.tsx create mode 100644 kobo/apps/hook/utils/tests/__init__.py create mode 100644 kobo/apps/hook/utils/tests/mixins.py create mode 100644 kobo/apps/openrosa/apps/logger/migrations/0038_add_mongo_uuid_field_to_xform.py create mode 100644 kobo/apps/openrosa/apps/logger/migrations/0039_populate_counters.py create mode 100644 kobo/apps/openrosa/apps/main/migrations/0017_userprofile_submissions_suspended.py delete mode 100644 kobo/apps/openrosa/apps/main/service_health.py delete mode 100644 kobo/apps/organizations/admin.py create mode 100644 kobo/apps/organizations/admin/__init__.py create mode 100644 kobo/apps/organizations/admin/organization.py create mode 100644 kobo/apps/organizations/admin/organization_invite.py create mode 100644 kobo/apps/organizations/admin/organization_owner.py create mode 100644 kobo/apps/organizations/admin/organization_user.py create mode 100644 kobo/apps/organizations/exceptions.py create mode 100644 kobo/apps/organizations/forms.py create mode 100644 kobo/apps/organizations/tasks.py rename kobo/apps/organizations/tests/{test_organization.py => test_organizations.py} (79%) create mode 100644 kobo/apps/organizations/tests/test_organizations_model.py create mode 100644 kobo/apps/organizations/types.py create mode 100644 kobo/apps/project_ownership/migrations/0003_create_proxy_and_add_invite_type.py create mode 100644 kobo/apps/stripe/admin.py create mode 100644 kobo/apps/stripe/migrations/0001_initial.py create mode 100644 kobo/apps/stripe/migrations/__init__.py create mode 100644 kobo/apps/stripe/models.py create mode 100644 kobo/apps/stripe/templates/admin/add-ons/change_list.html create mode 100644 kobo/apps/trackers/tests/test_utils.py create mode 100644 kpi/migrations/0061_rename_synchronousexport_submissionssynchronousexport.py create mode 100644 kpi/migrations/0062_rename_exporttask_submissionsexporttask.py create mode 100644 kpi/tests/test_cache_utils.py delete mode 100644 kpi/tests/test_organization.py create mode 100644 kpi/tests/utils/mixins.py diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4d94ea64e3..106021ed79 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -36,20 +36,22 @@ /jsapp/ @magicznyleszek /patches/ @p2edwards /static/ @magicznyleszek -/webpack/ @magicznyleszek -/.babelrc.json @magicznyleszek -/.browserlistrc @magicznyleszek -/.eslintignore @magicznyleszek -/.eslintrc.js @magicznyleszek -/.node-version @magicznyleszek -/.nvmrc @magicznyleszek -/.prettierrc.js @magicznyleszek -/.stylelintrc.js @magicznyleszek -/.swcrc @magicznyleszek -/.coffeelnt.json @magicznyleszek -/package-lock.json @magicznyleszek -/package.json @magicznyleszek -/tsconfig.json @magicznyleszek +/static/js/ @magicznyleszek @p2edwards +/test/ @magicznyleszek @p2edwards +/webpack/ @magicznyleszek @p2edwards +/.babelrc.json @magicznyleszek @p2edwards +/.browserslistrc @magicznyleszek @p2edwards +/.eslintignore @magicznyleszek @p2edwards +/.eslintrc.js @magicznyleszek @p2edwards +/.node-version @magicznyleszek @p2edwards +/.nvmrc @magicznyleszek @p2edwards +/.prettierrc.js @magicznyleszek @p2edwards +/.stylelintrc.js @magicznyleszek @p2edwards +/.swcrc @magicznyleszek @p2edwards +/.coffeelint.json @magicznyleszek @p2edwards +/package-lock.json @magicznyleszek @p2edwards +/package.json @magicznyleszek @p2edwards +/tsconfig.json @magicznyleszek @p2edwards # Billing /jsapp/js/account/ @jamesrkiger @@ -64,11 +66,12 @@ # Default owner /dependencies/ @jnm @noliveleger /hub/ @jnm @noliveleger +/hub/tests/ @jnm @noliveleger /kobo/ @jnm @noliveleger /kobo/apps/audit_log/ @rgraber /kobo/apps/subsequences/ @Guitlle /kpi/ @jnm @noliveleger -/test/ @jnm @noliveleger +/kpi/tests/ @jnm @noliveleger /.coveragerc @jnm /.dockerignore @jnm @noliveleger /format-python.sh @noliveleger @@ -76,6 +79,12 @@ /pip-compile.sh @jnm @noliveleger /pyproject.toml @jnm @noliveleger +# Django Static Templates, HTML, JS, CSS +/kobo/apps/accounts/templates/ @magicznyleszek @p2edwards @jnm @noliveleger +/kpi/templates/ @magicznyleszek @p2edwards @jnm @noliveleger +/kpi/static/css/ @magicznyleszek @p2edwards +_registration.scss @magicznyleszek @p2edwards + @@ -84,7 +93,9 @@ /docker/ @bufke @jnm @noliveleger /scripts/ @bufke @jnm @noliveleger +/scripts/*.js @magicznyleszek @p2edwards /.github/ @bufke @jnm @noliveleger @magicznyleszek +/.github/workflows/npm-test.yml @bufke @jnm @noliveleger @magicznyleszek @p2edwards /.gitlab-ci.yml @bufke /Dockerfile @bufke @jnm @noliveleger @@ -95,8 +106,8 @@ #### Documentation section /CONTRIBUTING.md @Akuukis @magicznyleszek @noliveleger /README.md @Akuukis @jnm @magicznyleszek @noliveleger -/.github/CODEOWNERS.md @Akuukis @jnm @noliveleger @magicznyleszek -/.github/FUNDING.md @Akuukis @jnm @noliveleger @magicznyleszek +/.github/CODEOWNERS @Akuukis @jnm @noliveleger @magicznyleszek +/.github/FUNDING.yml @Akuukis @jnm @noliveleger @magicznyleszek /.github/ISSUE_TEMPLATE.md @Akuukis @jnm @noliveleger @magicznyleszek /.github/PULL_REQUEST_TEMPLATE.md @Akuukis @jnm @noliveleger @magicznyleszek diff --git a/README.md b/README.md index fbbd76336c..86ae437103 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # KPI -[![Python Build Status](https://github.com/kobotoolbox/kpi/workflows/pytest/badge.svg?branch=main)](https://github.com/kobotoolbox/kpi/actions?query=workflow%3Apytest+branch%3Amain) +[![Python Build Status](https://github.com/kobotoolbox/kpi/actions/workflows/pytest.yml/badge.svg?branch=main)](https://github.com/kobotoolbox/kpi/actions?query=workflow%3Apytest+branch%3Amain) [![Python Coverage Status](https://coveralls.io/repos/github/kobotoolbox/kpi/badge.svg?branch=main)](https://coveralls.io/github/kobotoolbox/kpi?branch=main) -[![JavaScript Build Status](https://github.com/kobotoolbox/kpi/workflows/npm-test/badge.svg?branch=main)](https://github.com/kobotoolbox/kpi/actions?query=workflow%3Anpm-test+branch%3Amain) +[![JavaScript Build Status](https://github.com/kobotoolbox/kpi/actions/workflows/npm-test.yml/badge.svg?branch=main)](https://github.com/kobotoolbox/kpi/actions?query=workflow%3Anpm-test+branch%3Amain) For production always use a specific release branch, `main` branch may include breaking changes. Run `git branch -rl 'origin/release/*'` to list release branches and then switch to a release branch of your choice. diff --git a/dependencies/pip/dev_requirements.txt b/dependencies/pip/dev_requirements.txt index 13c4b905f7..1df8bbb9f1 100644 --- a/dependencies/pip/dev_requirements.txt +++ b/dependencies/pip/dev_requirements.txt @@ -414,7 +414,7 @@ oauthlib==3.2.2 # -r dependencies/pip/requirements.in # django-oauth-toolkit # requests-oauthlib -openpyxl==3.0.9 +openpyxl==3.1.3 # via # -r dependencies/pip/requirements.in # pyxform @@ -537,7 +537,7 @@ pytz==2024.1 # via # flower # pandas -pyxform==1.9.0 +pyxform==2.2.0 # via # -r dependencies/pip/requirements.in # formpack diff --git a/dependencies/pip/requirements.in b/dependencies/pip/requirements.in index 5db53d0e5e..968f5b6ba8 100644 --- a/dependencies/pip/requirements.in +++ b/dependencies/pip/requirements.in @@ -75,7 +75,7 @@ openpyxl psycopg pymongo python-dateutil -pyxform==1.9.0 +pyxform==2.2.0 requests regex responses diff --git a/dependencies/pip/requirements.txt b/dependencies/pip/requirements.txt index 41e5731fa0..76175a5dc5 100644 --- a/dependencies/pip/requirements.txt +++ b/dependencies/pip/requirements.txt @@ -336,7 +336,7 @@ oauthlib==3.2.2 # -r dependencies/pip/requirements.in # django-oauth-toolkit # requests-oauthlib -openpyxl==3.0.9 +openpyxl==3.1.3 # via # -r dependencies/pip/requirements.in # pyxform @@ -412,7 +412,7 @@ pytz==2024.1 # via # flower # pandas -pyxform==1.9.0 +pyxform==2.2.0 # via # -r dependencies/pip/requirements.in # formpack diff --git a/hub/admin/extend_user.py b/hub/admin/extend_user.py index 47116f5ede..b962f2a1ad 100644 --- a/hub/admin/extend_user.py +++ b/hub/admin/extend_user.py @@ -25,6 +25,7 @@ from kobo.apps.trash_bin.models.account import AccountTrash from kobo.apps.trash_bin.utils import move_to_trash from kpi.models.asset import AssetDeploymentStatus + from .filters import UserAdvancedSearchFilter from .mixins import AdvancedSearchMixin @@ -87,8 +88,10 @@ class OrgInline(admin.StackedInline): 'organization', 'is_admin', ] + can_delete = False + # Override H2 style to make inline section like other fieldsets + classes = ('no-upper',) raw_id_fields = ('user', 'organization') - readonly_fields = settings.STRIPE_ENABLED and ('active_subscription_status',) or [] def active_subscription_status(self, obj): if settings.STRIPE_ENABLED: @@ -98,6 +101,12 @@ def active_subscription_status(self, obj): else 'None' ) + def get_readonly_fields(self, request, obj=None): + readonly_fields = ['organization', 'is_admin'] + if settings.STRIPE_ENABLED: + readonly_fields.append('active_subscription_status') + return readonly_fields + def has_add_permission(self, request, obj=OrganizationUser): return False @@ -158,6 +167,9 @@ class ExtendedUserAdmin(AdvancedSearchMixin, UserAdmin): ) actions = ['remove', 'delete'] + class Media: + css = {'all': ('admin/css/inline_as_fieldset.css',)} + @admin.action(description='Remove selected users (delete everything but their username)') def remove(self, request, queryset, **kwargs): """ @@ -235,8 +247,9 @@ def get_queryset(self, request): ) def get_search_results(self, request, queryset, search_term): - if request.path != '/admin/auth/user/': + queryset = self._filter_queryset(request, queryset) + # If search comes from autocomplete field, use parent class method return super(UserAdmin, self).get_search_results( request, queryset, search_term @@ -261,6 +274,32 @@ def monthly_submission_count(self, obj): ).aggregate(counter=Sum('counter')) return instances.get('counter') + def _filter_queryset(self, request, queryset): + auto_complete = request.path == '/admin/autocomplete/' + app_label = request.GET.get('app_label') + model_name = request.GET.get('model_name') + + if ( + auto_complete + and app_label == 'organizations' + and model_name == 'organizationuser' + ): + return self._filter_queryset_for_organization_user(queryset) + + return queryset + + def _filter_queryset_for_organization_user(self, queryset): + """ + Displays only users whose organization has a single member. + """ + return ( + queryset.annotate( + user_count=Count('organizations_organization__organization_users') + ) + .filter(user_count__lte=1) + .order_by('username') + ) + def _remove_or_delete( self, request, diff --git a/hub/models/extra_user_detail.py b/hub/models/extra_user_detail.py index 012a28b676..95d27d650b 100644 --- a/hub/models/extra_user_detail.py +++ b/hub/models/extra_user_detail.py @@ -78,5 +78,6 @@ def _sync_org_name(self): except (KeyError, AttributeError): organization_name = None - user_organization.name = organization_name - user_organization.save(update_fields=['name']) + if organization_name: + user_organization.name = organization_name + user_organization.save(update_fields=['name']) diff --git a/hub/static/admin/css/inline_as_fieldset.css b/hub/static/admin/css/inline_as_fieldset.css new file mode 100644 index 0000000000..fc35ae7805 --- /dev/null +++ b/hub/static/admin/css/inline_as_fieldset.css @@ -0,0 +1,3 @@ +.no-upper h2 { + text-transform: unset; +} diff --git a/jsapp/js/account/accountSidebar.tsx b/jsapp/js/account/accountSidebar.tsx index a8ef94ca45..41aa3a54ba 100644 --- a/jsapp/js/account/accountSidebar.tsx +++ b/jsapp/js/account/accountSidebar.tsx @@ -48,10 +48,6 @@ function AccountSidebar() { setShowPlans(true); }, [subscriptionStore.isInitialised]); - const showAddOnsLink = useMemo(() => { - return !subscriptionStore.planResponse.length; - }, [subscriptionStore.isInitialised]); - return (