Skip to content

Commit

Permalink
source for email/name: migrate from AMS to RHSSO
Browse files Browse the repository at this point in the history
  • Loading branch information
goneri committed Aug 29, 2024
1 parent a1274bb commit 72d5fe5
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 31 deletions.
17 changes: 6 additions & 11 deletions ansible_ai_connect/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,25 @@


def create_user(
username: str = None,
password: str = None,
provider: str = None,
email: str = None,
social_auth_extra_data: any = {},
external_username: str = "",
rh_user_is_org_admin: Optional[bool] = None,
rh_user_id: str = None,
rh_org_id: int = 1234567,
org_opt_out: bool = False,
**kwargs,
):
(org, _) = Organization.objects.get_or_create(id=rh_org_id, telemetry_opt_out=org_opt_out)
username = username or "u" + "".join(random.choices(string.digits, k=5))
password = password or "secret"
email = email or username + "@example.com"
kwargs.setdefault("username", "u" + "".join(random.choices(string.digits, k=5)))
kwargs.setdefault("password", "secret")
kwargs.setdefault("email", kwargs["username"] + "@example.com")
user = get_user_model().objects.create_user(
username=username,
email=email,
password=password,
organization=org if provider == USER_SOCIAL_AUTH_PROVIDER_OIDC else None,
**kwargs,
)
if provider:
rh_user_id = rh_user_id or str(uuid4())
user.external_username = external_username or username
user.external_username = kwargs.get("external_username") or kwargs.get("username")
social_auth = UserSocialAuth.objects.create(user=user, provider=provider, uid=rh_user_id)
social_auth.set_extra_data(social_auth_extra_data)
if rh_user_is_org_admin:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3

# Copyright Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand

User = get_user_model()


class Command(BaseCommand):
help = "Initialize the email and names field from the AMS"

def handle(self, *args, **options):
cpt = 0
for user in User.objects.all():
if user.first_name:
continue
ams_data = user.ams()
if not ams_data:
continue
user.given_name = ams_data.get("first_name")
user.family_name = ams_data.get("last_name")
user.email = ams_data.get("email")
user.save()
cpt += 1

self.stdout.write(f"{cpt} users migrated.")
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3

# Copyright Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from io import StringIO

from django.contrib.auth import get_user_model
from django.core.management import call_command
from django.test import override_settings

from ansible_ai_connect.test_utils import WisdomServiceAPITestCaseBaseOIDC

User = get_user_model()


@override_settings(AUTHZ_BACKEND_TYPE="dummy")
class TestMigrate(WisdomServiceAPITestCaseBaseOIDC):
def call_command(self, *args, **kwargs):
out = StringIO()
call_command(
"migrate_email_name_from_ams",
*args,
stdout=out,
stderr=StringIO(),
**kwargs,
)
return out.getvalue()

def test_migrate(self):
original = (self.user.email, self.user.given_name, self.user.family_name)

out = self.call_command()
self.assertIn("1 users migrated", out)
self.user = User.objects.get(id=self.user.id)
self.assertNotEqual(
original, (self.user.email, self.user.given_name, self.user.family_name)
)
self.assertEqual(self.user.given_name, "Robert")
12 changes: 5 additions & 7 deletions ansible_ai_connect/users/reports/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,11 @@ def generate(
["First name", "Last name", "Organization name", "Plan name", "Trial started"]
)
for user in users:
ams = user.get("ams")
organization = user.get("organization")
for plan in user.get("userplan_set"):
row_data = [
ams.get("first_name"),
ams.get("last_name"),
user.get("given_name"),
user.get("family_name"),
organization.get("name"),
plan.get("plan").get("name"),
plan.get("created_at"),
Expand All @@ -105,13 +104,12 @@ def generate(
writer = csv.writer(output)
writer.writerow(["First name", "Last name", "Email", "Plan name", "Trial started"])
for user in users:
ams = user.get("ams")
for plan in user.get("userplan_set"):
if plan.get("accept_marketing"):
row_data = [
ams.get("first_name"),
ams.get("last_name"),
ams.get("email"),
user.get("given_name"),
user.get("family_name"),
user.get("email"),
plan.get("plan").get("name"),
plan.get("created_at"),
]
Expand Down
2 changes: 2 additions & 0 deletions ansible_ai_connect/users/reports/tests/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def initialise(self, test: WisdomServiceAPITestCaseBaseOIDC):
# A User that has a trial plan
# DummyCheck/AUTHZ_BACKEND_TYPE=dummy sets the User's name to "Robert Surcouf"
self.trial_user = create_user_with_provider(
given_name="Robert",
family_name="Surcouf",
username="trial_user",
email="trial_user@somewhere.com",
provider=USER_SOCIAL_AUTH_PROVIDER_OIDC,
Expand Down
10 changes: 6 additions & 4 deletions ansible_ai_connect/users/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ class UserResponseSerializer(serializers.Serializer):
# Implemented as a vanilla Serializer as ModelSerializer is driven by the Model definition.
# Field 'org_telemetry_opt_out' is an extension to the CurrentUserView response dependent
# upon whether the Telemetry Opt In/Out feature has been enabled.
email = serializers.CharField(required=False)
external_username = serializers.CharField(required=False)
family_name = serializers.CharField(required=False)
given_name = serializers.CharField(required=False)
org_telemetry_opt_out = serializers.BooleanField(required=False)
organization = OrganizationSerializer(required=False)
rh_org_has_subscription = serializers.BooleanField(read_only=True)
rh_user_has_seat = serializers.BooleanField(read_only=True)
rh_user_is_org_admin = serializers.BooleanField(required=False)
external_username = serializers.CharField(required=False)
username = serializers.CharField(required=True, max_length=150)
ams = serializers.DictField(required=False)
org_telemetry_opt_out = serializers.BooleanField(required=False)
userplan_set = UserPlanSerializer(many=True)
organization = OrganizationSerializer(required=False)


class MarkdownUserResponseSerializer(serializers.Serializer):
Expand Down
21 changes: 12 additions & 9 deletions tools/openapi-schema/ansible-ai-connect-service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,18 @@ components:
UserResponse:
type: object
properties:
email:
type: string
external_username:
type: string
family_name:
type: string
given_name:
type: string
org_telemetry_opt_out:
type: boolean
organization:
$ref: '#/components/schemas/Organization'
rh_org_has_subscription:
type: boolean
readOnly: true
Expand All @@ -1034,22 +1046,13 @@ components:
readOnly: true
rh_user_is_org_admin:
type: boolean
external_username:
type: string
username:
type: string
maxLength: 150
ams:
type: object
additionalProperties: {}
org_telemetry_opt_out:
type: boolean
userplan_set:
type: array
items:
$ref: '#/components/schemas/UserPlan'
organization:
$ref: '#/components/schemas/Organization'
required:
- rh_org_has_subscription
- rh_user_has_seat
Expand Down

0 comments on commit 72d5fe5

Please sign in to comment.