Skip to content

Commit

Permalink
feat: extend the generic gen functionality
Browse files Browse the repository at this point in the history
* besides user and user facility attributes, the extended generator will generate also member, member-resource, user and user-facility attributes
* link_id serves to link users with their members without exposing the internal user id
* the changes should help us making more services by reusing the same function call
  • Loading branch information
Johaney-s committed Jun 1, 2023
1 parent 54176a8 commit 3863d90
Showing 1 changed file with 181 additions and 33 deletions.
214 changes: 181 additions & 33 deletions gen/perunDataGenerator.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,85 @@ use Exporter 'import';
our $JSON_FORMAT = "json";
our @EXPORT = qw($JSON_FORMAT);

our $A_MEMBER_STATUS; *A_MEMBER_STATUS = \'urn:perun:member:attribute-def:core:status';
our $USER_ATTR_PREFIX = "urn:perun:user:";
our $USER_FACILITY_ATTR_PREFIX = "urn:perun:user_facility:";
our $MEMBER_ATTR_PREFIX = "urn:perun:member:";
our $MEMBER_RESOURCE_ATTR_PREFIX = "urn:perun:member_resource:";
our $RESOURCE_ATTR_PREFIX = "urn:perun:resource:";
our $FACILITY_ATTR_PREFIX = "urn:perun:facility:";

# Generate user and user_facility required attributes for each user into JSON file.
# Subroutine uses perunServicesInit which REQUIRE access to $::SERVICE_NAME and $::PROTOCOL_VERSION.
# This can be achieved by following lines in your main script: (for example)
# local $::SERVICE_NAME = "passwd";
# local $::PROTOCOL_VERSION = "3.0.0";
# If not valid VO members should be skipped, member status attribute needs to be set on service and set
# local $::SKIP_NON_VALID_MEMBERS = 1;
sub generateUsersDataInJSON {
perunServicesInit::init;
our $A_MEMBER_STATUS; *A_MEMBER_STATUS = \'urn:perun:member:attribute-def:core:status';

my $DIRECTORY = perunServicesInit::getDirectory;
my $data = perunServicesInit::getHashedHierarchicalData;
my $agent = perunServicesInit->getAgent;
my $attributesAgent = $agent->getAttributesAgent;
my $servicesAgent = $agent->getServicesAgent;
my $service = $servicesAgent->getServiceByName( name => $::SERVICE_NAME);
# Returns attribute definitions related to specified entity (entities) type(s)
sub getRequiredAttributesByType {
my $requiredAttributesDefinitions = shift;
my $attributePrefix = shift;
my @requiredAttributes = ();

my @requiredAttributesDefinitions = $attributesAgent->getRequiredAttributesDefinition(service => $service->getId);
my @userRequiredAttributes = ();
my @userFacilityRequiredAttributes = ();
foreach my $attrDef (@requiredAttributesDefinitions) {
# if attribute's namespace starts with "urn:perun:user:"
my $o = index $attrDef->getNamespace, "urn:perun:user:";
foreach my $attrDef (@$requiredAttributesDefinitions) {
my $o = index $attrDef->getNamespace, $attributePrefix;
if ($o == 0) {
push @userRequiredAttributes, $attrDef;
push @requiredAttributes, $attrDef;
next;
}
$o = index $attrDef->getNamespace, "urn:perun:user_facility:";
if ($o == 0) {
push @userFacilityRequiredAttributes, $attrDef;
}

return @requiredAttributes;
}

sub prepareMembersData {
my $data = shift;
my $userIds = shift;
my $resourceId = shift;
my $memberRequiredAttributes = shift;
my $memberResourceRequiredAttributes = shift;

my @members = ();
foreach my $memberId ($data->getMemberIdsForResource(resource => $resourceId)) {
my $memberData = {};
my $perunUserId = $data->getUserIdForMember(member => $memberId);
if (! exists $userIds->{$perunUserId}) {
# user was skipped
next;
}
$memberData->{"link_id"} = $userIds->{$perunUserId};

foreach my $memberAttribute (@$memberRequiredAttributes) {
my $attrValue = $data->getMemberAttributeValue(member => $memberId, attrName => $memberAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($memberAttribute->getType eq "boolean" && !defined $attrValue) {
$memberData->{$memberAttribute->getName} = \0;
} else {
$memberData->{$memberAttribute->getName} = $attrValue;
}
}

foreach my $memberResourceAttribute (@$memberResourceRequiredAttributes) {
my $attrValue = $data->getMemberResourceAttributeValue(member => $memberId, resource => $resourceId, attrName => $memberResourceAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($memberResourceAttribute->getType eq "boolean" && !defined $attrValue) {
$memberData->{$memberResourceAttribute->getName} = \0;
} else {
$memberData->{$memberResourceAttribute->getName} = $attrValue;
}
}

push @members, $memberData;
}
my @users;
return \@members;
}

# Prepares structure of user attributes
# If addLinkId is true, it will add "link_id" property which is returned in the usersIds structure as {"perunUserId": linkId}
sub prepareUsersData {
my $data = shift;
my $userRequiredAttributes = shift;
my $userFacilityRequiredAttributes = shift;
my $addLinkId = shift;

####### prepare data ######################
my %usersIds = ();
my $linkIdCounter = 0;
my @users = ();
foreach my $memberId ($data->getMemberIdsForFacility()) {

if ($::SKIP_NON_VALID_MEMBERS) {
Expand All @@ -58,11 +98,12 @@ sub generateUsersDataInJSON {
if (exists($usersIds{$userId})) {
next;
} else {
$usersIds{$userId} = 0;
$linkIdCounter++;
$usersIds{$userId} = $linkIdCounter;
}
my $userData = {};

foreach my $userAttribute (@userRequiredAttributes) {
foreach my $userAttribute (@$userRequiredAttributes) {
my $attrValue = $data->getUserAttributeValue(member => $memberId, attrName => $userAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($userAttribute->getType eq "boolean" && !defined $attrValue) {
Expand All @@ -72,7 +113,7 @@ sub generateUsersDataInJSON {
}
}

foreach my $userFacilityAttribute (@userFacilityRequiredAttributes) {
foreach my $userFacilityAttribute (@$userFacilityRequiredAttributes) {
my $attrValue = $data->getUserFacilityAttributeValue(member => $memberId, attrName => $userFacilityAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($userFacilityAttribute->getType eq "boolean" && !defined $attrValue) {
Expand All @@ -81,13 +122,120 @@ sub generateUsersDataInJSON {
$userData->{$userFacilityAttribute->getName} = $attrValue;
}
}

if ($addLinkId) {
$userData->{"link_id"} = $linkIdCounter;
}
push @users, $userData;
}

####### output file ######################
return (\@users, \%usersIds);
}

=c
Generate user and user_facility required attributes for each user into JSON file.
Subroutine uses perunServicesInit which REQUIRE access to $::SERVICE_NAME and $::PROTOCOL_VERSION.
This can be achieved by following lines in your main script: (for example)
local $::SERVICE_NAME = "passwd";
local $::PROTOCOL_VERSION = "3.0.0";
If not valid VO members should be skipped, member status attribute needs to be set on service and set
local $::SKIP_NON_VALID_MEMBERS = 1;
=cut
sub generateUsersDataInJSON {
perunServicesInit::init;

my $DIRECTORY = perunServicesInit::getDirectory;
my $data = perunServicesInit::getHashedHierarchicalData;
my $agent = perunServicesInit->getAgent;
my $attributesAgent = $agent->getAttributesAgent;
my $servicesAgent = $agent->getServicesAgent;
my $service = $servicesAgent->getServiceByName( name => $::SERVICE_NAME);

my @requiredAttributesDefinitions = $attributesAgent->getRequiredAttributesDefinition(service => $service->getId);
my @userRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $USER_ATTR_PREFIX);
my @userFacilityRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $USER_FACILITY_ATTR_PREFIX);

my ($users, $ids) = prepareUsersData($data, \@userRequiredAttributes, \@userFacilityRequiredAttributes);

my $fileName = "$DIRECTORY/$::SERVICE_NAME";
open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
print FILE JSON::XS->new->utf8->pretty->canonical->encode($users);
close FILE or die "Cannot close $fileName: $! \n";

perunServicesInit::finalize;
}

=c
Generate user, user_facility, member, member_resource, resource and facility required attributes into JSON file.
The result structure is:
{
"facility_attribute_name": "facility_attribute_value",
"users" => [{"user_attribute_name": "user_attribute_value",
"link_id": id linking user to its members}]
"groups" => [{"resource_attribute_name": "resource_attribute_value",
"members": [{"member_attribute_name": "member_attribute_value",
"link_id": id of user this member belongs to}]}]
}
Subroutine uses perunServicesInit which REQUIRE access to $::SERVICE_NAME and $::PROTOCOL_VERSION.
This can be achieved by following lines in your main script: (for example)
local $::SERVICE_NAME = "passwd";
local $::PROTOCOL_VERSION = "3.0.0";
If not valid VO members should be skipped, member status attribute needs to be set on service and set
local $::SKIP_NON_VALID_MEMBERS = 1;
=cut
sub generateMemberUsersDataInJson {
perunServicesInit::init;

my $DIRECTORY = perunServicesInit::getDirectory;
my $data = perunServicesInit::getHashedHierarchicalData;
my $agent = perunServicesInit->getAgent;
my $attributesAgent = $agent->getAttributesAgent;
my $servicesAgent = $agent->getServicesAgent;
my $service = $servicesAgent->getServiceByName( name => $::SERVICE_NAME);

my @requiredAttributesDefinitions = $attributesAgent->getRequiredAttributesDefinition(service => $service->getId);

my @userRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $USER_ATTR_PREFIX);
my @userFacilityRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $USER_FACILITY_ATTR_PREFIX);
my ($users, $userIds) = prepareUsersData($data, \@userRequiredAttributes, \@userFacilityRequiredAttributes, 1);

my @facilityRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $FACILITY_ATTR_PREFIX);
my @resourceRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $RESOURCE_ATTR_PREFIX);
my @memberRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $MEMBER_ATTR_PREFIX);
my @memberResourceRequiredAttributes = getRequiredAttributesByType(\@requiredAttributesDefinitions, $MEMBER_RESOURCE_ATTR_PREFIX);

my $result = {};
$result->{"users"} = $users;
$result->{"groups"} = ();

foreach my $facilityAttribute (@facilityRequiredAttributes) {
my $attrValue = $data->getFacilityAttributeValue(attrName => $facilityAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($facilityAttribute->getType eq "boolean" && !defined $attrValue) {
$result->{$facilityAttribute->getName} = \0;
} else {
$result->{$facilityAttribute->getName} = $attrValue;
}
}

foreach my $resourceId ($data->getResourceIds()) {
my $resource = {};
foreach my $resourceAttribute (@resourceRequiredAttributes) {
my $attrValue = $data->getResourceAttributeValue(resource => $resourceId, attrName => $resourceAttribute->getName);
# In case there is an undefined boolean attribute, we have to change it to false
if ($resourceAttribute->getType eq "boolean" && !defined $attrValue) {
$resource->{$resourceAttribute->getName} = \0;
} else {
$resource->{$resourceAttribute->getName} = $attrValue;
}
}
$resource->{"members"} = prepareMembersData($data, $userIds, $resourceId, \@memberRequiredAttributes, \@memberResourceRequiredAttributes);
push @{$result->{"groups"}}, $resource;
}

my $fileName = "$DIRECTORY/$::SERVICE_NAME";
open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
print FILE JSON::XS->new->utf8->pretty->canonical->encode(\@users);
print FILE JSON::XS->new->utf8->pretty->canonical->encode($result);
close FILE or die "Cannot close $fileName: $! \n";

perunServicesInit::finalize;
Expand Down

0 comments on commit 3863d90

Please sign in to comment.