Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(organization): export organization users asynchronously from Admin interface TASK-1478 #5448

Merged
merged 3 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions dependencies/pip/dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ django==4.2.15
# django-filter
# django-guardian
# django-import-export
# django-import-export-celery
# django-markdownx
# django-oauth-toolkit
# django-organizations
Expand All @@ -174,6 +175,8 @@ django-allauth==65.1.0
# via -r dependencies/pip/requirements.in
django-amazon-ses==4.0.1
# via -r dependencies/pip/requirements.in
django-author==1.2.0
# via django-import-export-celery
django-braces==1.15.0
# via -r dependencies/pip/requirements.in
django-celery-beat==2.6.0
Expand All @@ -197,6 +200,10 @@ django-filter==24.2
django-guardian==2.4.0
# via -r dependencies/pip/requirements.in
django-import-export==4.1.0
# via
# -r dependencies/pip/requirements.in
# django-import-export-celery
django-import-export-celery==1.7.1
# via -r dependencies/pip/requirements.in
django-loginas==0.3.11
# via -r dependencies/pip/requirements.in
Expand Down Expand Up @@ -331,6 +338,8 @@ grpcio==1.62.1
# grpcio-status
grpcio-status==1.62.1
# via google-api-core
html2text==2024.2.26
# via django-import-export-celery
httmock==1.4.0
# via -r dependencies/pip/dev_requirements.in
httplib2==0.22.0
Expand Down Expand Up @@ -578,6 +587,8 @@ sentinels==1.0.0
# via mongomock
sentry-sdk==1.44.0
# via -r dependencies/pip/requirements.in
setuptools-git==1.2
# via django-author
shortuuid==1.0.13
# via -r dependencies/pip/requirements.in
simplejson==3.19.2
Expand Down
1 change: 1 addition & 0 deletions dependencies/pip/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ django-debug-toolbar
django-environ
django-filter
django-import-export
django-import-export-celery
django-extensions
django-oauth-toolkit
django-organizations
Expand Down
11 changes: 11 additions & 0 deletions dependencies/pip/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ django==4.2.15
# django-filter
# django-guardian
# django-import-export
# django-import-export-celery
# django-markdownx
# django-oauth-toolkit
# django-organizations
Expand All @@ -142,6 +143,8 @@ django-allauth==65.1.0
# via -r dependencies/pip/requirements.in
django-amazon-ses==4.0.1
# via -r dependencies/pip/requirements.in
django-author==1.2.0
# via django-import-export-celery
django-braces==1.15.0
# via -r dependencies/pip/requirements.in
django-celery-beat==2.6.0
Expand All @@ -165,6 +168,10 @@ django-filter==24.2
django-guardian==2.4.0
# via -r dependencies/pip/requirements.in
django-import-export==4.1.0
# via
# -r dependencies/pip/requirements.in
# django-import-export-celery
django-import-export-celery==1.7.1
# via -r dependencies/pip/requirements.in
django-loginas==0.3.11
# via -r dependencies/pip/requirements.in
Expand Down Expand Up @@ -277,6 +284,8 @@ grpcio==1.62.1
# grpcio-status
grpcio-status==1.62.1
# via google-api-core
html2text==2024.2.26
# via django-import-export-celery
httplib2==0.22.0
# via
# google-api-python-client
Expand Down Expand Up @@ -447,6 +456,8 @@ s3transfer==0.10.1
# via boto3
sentry-sdk==1.44.0
# via -r dependencies/pip/requirements.in
setuptools-git==1.2
# via django-author
shortuuid==1.0.13
# via -r dependencies/pip/requirements.in
six==1.16.0
Expand Down
5 changes: 5 additions & 0 deletions kobo/apps/organizations/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export.widgets import ForeignKeyWidget
from import_export_celery.admin_actions import create_export_job_action
from organizations.base_admin import (
BaseOrganizationAdmin,
BaseOrganizationOwnerAdmin,
Expand Down Expand Up @@ -53,6 +54,10 @@ class Meta:
class OrgUserAdmin(ImportExportModelAdmin, BaseOrganizationUserAdmin):
resource_classes = [OrgUserResource]

actions = (
create_export_job_action,
)


@admin.register(OrganizationOwner)
class OrgOwnerAdmin(BaseOrganizationOwnerAdmin):
Expand Down
7 changes: 7 additions & 0 deletions kobo/apps/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ def active_subscription_status(self):
"""
return ', '.join(self.active_subscription_statuses)

@classmethod
def export_resource_classes(cls):
from .admin import OrgUserResource
return {
'organization_users': ('Organization users resource', OrgUserResource),
}


class OrganizationOwner(AbstractOrganizationOwner):
pass
Expand Down
36 changes: 32 additions & 4 deletions kobo/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
'allauth.usersessions',
'hub.HubAppConfig',
'import_export',
'import_export_celery',
'loginas',
'webpack_loader',
'django_extensions',
Expand Down Expand Up @@ -168,6 +169,7 @@
'hub.middleware.UsernameInResponseHeaderMiddleware',
'django_userforeignkey.middleware.UserForeignKeyMiddleware',
'django_request_cache.middleware.RequestCacheMiddleware',
'author.middlewares.AuthorDefaultBackendMiddleware',
]


Expand Down Expand Up @@ -1361,14 +1363,24 @@ def dj_stripe_request_callback_method():
)
if 'KPI_DEFAULT_FILE_STORAGE' in os.environ:
warnings.warn(
'KPI_DEFAULT_FILE_STORAGE is renamed DEFAULT_FILE_STORAGE, update the environment variable.',
'KPI_DEFAULT_FILE_STORAGE is renamed DEFAULT_FILE_STORAGE, '
'update the environment variable.',
DeprecationWarning,
)

# ToDo Find out why `private_storage.appconfig.PRIVATE_STORAGE_CLASS`
# cannot be imported. Otherwise, some tests are failing.
# from private_storage.appconfig import (
# PRIVATE_STORAGE_CLASS as DEFAULT_PRIVATE_STORAGE_CLASS
# )
# PRIVATE_STORAGE_CLASS = DEFAULT_PRIVATE_STORAGE_CLASS
PRIVATE_STORAGE_CLASS = 'private_storage.storage.files.PrivateFileSystemStorage'

if default_file_storage:

global_default_file_storage = STORAGES['default']['BACKEND']
default_file_storage = STORAGES['default']['BACKEND'] = default_file_storage

if default_file_storage != global_default_file_storage:
if default_file_storage.endswith('S3Boto3Storage'):
# To use S3 storage, set this to `kobo.apps.storage_backends.s3boto3.S3Boto3Storage`
Expand All @@ -1389,20 +1401,22 @@ def dj_stripe_request_callback_method():
'AZURE_URL_EXPIRATION_SECS', None
)

aws_storage_bucket_name = env.str('AWS_STORAGE_BUCKET_NAME', env.str('KPI_AWS_STORAGE_BUCKET_NAME', None))
aws_storage_bucket_name = env.str(
'AWS_STORAGE_BUCKET_NAME', env.str('KPI_AWS_STORAGE_BUCKET_NAME', None)
)
if aws_storage_bucket_name:
AWS_STORAGE_BUCKET_NAME = aws_storage_bucket_name
AWS_DEFAULT_ACL = 'private'
# django-private-storage needs its own S3 configuration
PRIVATE_STORAGE_CLASS = \
PRIVATE_STORAGE_CLASS = (
'private_storage.storage.s3boto3.PrivateS3BotoStorage'
# NB.........There's intentionally no 3 here! ^
)
AWS_PRIVATE_STORAGE_BUCKET_NAME = AWS_STORAGE_BUCKET_NAME
# Proxy S3 through our application instead of redirecting to bucket
# URLs with query parameter authentication
PRIVATE_STORAGE_S3_REVERSE_PROXY = True


if 'KOBOCAT_DEFAULT_FILE_STORAGE' in os.environ:
KOBOCAT_DEFAULT_FILE_STORAGE = os.environ.get('KOBOCAT_DEFAULT_FILE_STORAGE')
if 'KOBOCAT_AWS_STORAGE_BUCKET_NAME' in os.environ:
Expand All @@ -1416,6 +1430,8 @@ def dj_stripe_request_callback_method():
'KOBOCAT_MEDIA_ROOT', MEDIA_ROOT.replace('kpi', 'kobocat')
)

STORAGES['import_export_celery'] = {'BACKEND': PRIVATE_STORAGE_CLASS}

# Google Cloud Storage
# Not fully supported as a generic storage backend
GS_BUCKET_NAME = env.str('GS_BUCKET_NAME', None)
Expand Down Expand Up @@ -1795,3 +1811,15 @@ def dj_stripe_request_callback_method():
SILENCED_SYSTEM_CHECKS = ['guardian.W001']

DIGEST_LOGIN_FACTORY = 'django_digest.NoEmailLoginFactory'

# Import/Export Celery
IMPORT_EXPORT_CELERY_INIT_MODULE = 'kobo.celery'

IMPORT_EXPORT_CELERY_MODELS = {
'OrganizationUser': {
'app_label': 'organization',
'model_name': 'OrganizationUser',
},
}

IMPORT_EXPORT_CELERY_STORAGE_ALIAS = 'import_export_celery'
Loading