Skip to content

Commit

Permalink
feat: update license assign view to set source for assigned licenses
Browse files Browse the repository at this point in the history
  • Loading branch information
muhammad-ammar committed Sep 21, 2023
1 parent f9367ed commit 54ee2ac
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 4 deletions.
34 changes: 33 additions & 1 deletion license_manager/apps/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField

from license_manager.apps.subscriptions.constants import ACTIVATED, ASSIGNED
from django.core.validators import MinLengthValidator

from license_manager.apps.subscriptions.constants import ACTIVATED, ASSIGNED, SALESFORCE_ID_LENGTH
from license_manager.apps.subscriptions.models import (
CustomerAgreement,
License,
Expand Down Expand Up @@ -355,12 +357,42 @@ class Meta:
fields = LicenseAdminBulkActionSerializer.Meta.fields + CustomTextSerializer.Meta.fields


class SalesforceIdsSerializer(serializers.Serializer): # pylint: disable=abstract-method
"""
Serializer for specifying salesforce ids
Requires that a list of valid, non-empty salesforce ids are submitted.
"""
user_sfids = serializers.ListField(
child=serializers.CharField(
allow_blank=False,
write_only=True,
),
allow_empty=False,
required=False
)

class Meta:
fields = [
'user_sfids',
]


class LicenseAdminAssignActionSerializer(CustomTextWithMultipleEmailsSerializer): # pylint: disable=abstract-method
"""
Serializer for the license admin assign action.
"""

notify_users = serializers.BooleanField(required=False)
user_sfids = user_sfids = serializers.ListField(
child=serializers.CharField(
allow_blank=False,
write_only=True,
validators=[MinLengthValidator(SALESFORCE_ID_LENGTH)]
),
allow_empty=False,
required=False
)

class Meta:
fields = CustomTextWithMultipleEmailsSerializer.Meta.fields + [
Expand Down
37 changes: 35 additions & 2 deletions license_manager/apps/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
License,
SubscriptionPlan,
SubscriptionsRoleAssignment,
SubscriptionLicenseSource,
SubscriptionLicenseSourceType,
)
from license_manager.apps.subscriptions.utils import (
chunks,
Expand Down Expand Up @@ -726,6 +728,26 @@ def _assign_new_licenses(self, subscription_plan, user_emails):
)
return licenses

def _set_source_for_assigned_licenses(self, assigned_licenses, emails_and_sfids):
"""
Set source for each assigned license.
"""
license_source = SubscriptionLicenseSourceType.get_source_type(SubscriptionLicenseSourceType.AMT)
source_objects = []

Check warning on line 736 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L735-L736

Added lines #L735 - L736 were not covered by tests
for assigned_license in assigned_licenses:
sf_opportunity_id = emails_and_sfids.get(assigned_license.user_email)
source = SubscriptionLicenseSource(

Check warning on line 739 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L738-L739

Added lines #L738 - L739 were not covered by tests
license=assigned_license,
source_id=sf_opportunity_id,
source_type=license_source
)
source_objects.append(source)

Check warning on line 744 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L744

Added line #L744 was not covered by tests

SubscriptionLicenseSource.objects.bulk_create(

Check warning on line 746 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L746

Added line #L746 was not covered by tests
source_objects,
batch_size=constants.LICENSE_SOURCE_BULK_OPERATION_BATCH_SIZE
)

@action(detail=False, methods=['post'])
def assign(self, request, subscription_uuid=None): # pylint: disable=unused-argument
"""
Expand Down Expand Up @@ -769,8 +791,17 @@ def _assign(self, request, subscription_plan):
# Validate the user_emails and text sent in the data
self._validate_data(request.data)

# Dedupe all lowercase emails before turning back into a list for indexing
user_emails = list({email.lower() for email in request.data.get('user_emails', [])})
emails_and_sfids = None
# remove duplicate emails and convert to lowercase
if 'user_sfids' in request.data:
user_emails = map(str.lower, request.data.get('user_emails', []))
user_sfids = request.data.get('user_sfids', [])

Check warning on line 798 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L797-L798

Added lines #L797 - L798 were not covered by tests

emails_and_sfids = dict(zip(user_emails, user_sfids))
user_emails = list(emails_and_sfids.keys())

Check warning on line 801 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L800-L801

Added lines #L800 - L801 were not covered by tests
else:
# Dedupe all lowercase emails before turning back into a list for indexing
user_emails = list({email.lower() for email in request.data.get('user_emails', [])})

user_emails, already_associated_emails = self._trim_already_associated_emails(
subscription_plan,
Expand All @@ -795,6 +826,8 @@ def _assign(self, request, subscription_plan):
assigned_licenses = self._assign_new_licenses(
subscription_plan, user_emails,
)
if emails_and_sfids:
self._set_source_for_assigned_licenses(assigned_licenses, emails_and_sfids)

Check warning on line 830 in license_manager/apps/api/v1/views.py

View check run for this annotation

Codecov / codecov/patch

license_manager/apps/api/v1/views.py#L830

Added line #L830 was not covered by tests
except DatabaseError:
error_message = 'Database error occurred while assigning licenses, no assignments were completed'
logger.exception(error_message)
Expand Down
19 changes: 18 additions & 1 deletion license_manager/apps/subscriptions/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class LicenseAdmin(DjangoQLSearchMixin, admin.ModelAdmin):
'activation_key',
'get_renewed_to',
'get_renewed_from',
'auto_applied'
'auto_applied',
'source_id',
'source_type',
]
exclude = ['history', 'renewed_to']
list_display = (
Expand Down Expand Up @@ -79,8 +81,23 @@ class LicenseAdmin(DjangoQLSearchMixin, admin.ModelAdmin):
def get_queryset(self, request):
return super().get_queryset(request).select_related(
'subscription_plan',
'source'
)

@admin.display(description='Source ID')
def source_id(self, instance):
try:
return instance.source.source_id
except License.source.RelatedObjectDoesNotExist:
return ''

@admin.display(description='Source Type')
def source_type(self, instance):
try:
return instance.source.source_type.slug
except License.source.RelatedObjectDoesNotExist:
return ''

@admin.display(
description='Subscription Plan'
)
Expand Down
1 change: 1 addition & 0 deletions license_manager/apps/subscriptions/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class SegmentEvents:
# Bulk operation constants
LICENSE_BULK_OPERATION_BATCH_SIZE = 100
PENDING_ACCOUNT_CREATION_BATCH_SIZE = 100
LICENSE_SOURCE_BULK_OPERATION_BATCH_SIZE = 100

# Num distinct catalog query validation batch size
VALIDATE_NUM_CATALOG_QUERIES_BATCH_SIZE = 100
Expand Down

0 comments on commit 54ee2ac

Please sign in to comment.