Skip to content

Commit

Permalink
EPMRPP-91776 implement organization users dao
Browse files Browse the repository at this point in the history
  • Loading branch information
grabsefx committed Jul 8, 2024
1 parent b987e5f commit 565a04e
Show file tree
Hide file tree
Showing 89 changed files with 545 additions and 7,673 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dependencies {
if (releaseMode) {
compile 'com.epam.reportportal:commons'
} else {
implementation 'com.github.reportportal:commons:b6926df'
compile 'com.github.reportportal:commons:f4c73c1'
}

implementation 'io.swagger.core.v3:swagger-annotations:2.2.9'
Expand Down
5 changes: 3 additions & 2 deletions project-properties.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ project.ext {
releaseMode = project.hasProperty("releaseMode")
hasDBSchema = project.hasProperty("DB_SCHEMA_POSTGRES")
scriptsUrl = commonScriptsUrl + (releaseMode ? getProperty('scripts.version') : 'develop')
migrationsUrl = migrationsScriptsUrl + (releaseMode ? getProperty('migrations.version') : 'feature/orgs')
migrationsUrl = migrationsScriptsUrl + (releaseMode ? getProperty('migrations.version') : 'EPMRPP-91776-users-table')

//TODO refactor with archive download
testScriptsSrc = [
Expand Down Expand Up @@ -88,11 +88,12 @@ project.ext {
(migrationsUrl + '/migrations/200_migrate_org_roles.up.sql') : 'V200__migrate_org_roles.sql',
(migrationsUrl + '/migrations/201_drop_table_onboarding.up.sql') : 'V201__drop_table_onboarding.sql',
(migrationsUrl + '/migrations/202_update_project_table.up.sql') : 'V202__update_project_table.up.sql',
(migrationsUrl + '/migrations/203_user_table_extend.up.sql') : 'V203__user_table_extend.up.sql',

]
excludeTests = [
'com/epam/ta/reportportal/jooq/**',
'com/epam/ta/reportportal/model/**',
'com/epam/ta/reportportal/api/**',
'com/epam/ta/reportportal/config/**',
'com/epam/ta/reportportal/commons/accessible',
'com/epam/ta/reportportal/commons/querygen/constant',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
import static org.jooq.impl.DSL.choose;
import static org.jooq.impl.DSL.field;

import com.epam.reportportal.api.model.ProjectProfile;
import com.epam.ta.reportportal.commons.querygen.constant.TestItemCriteriaConstant;
import com.epam.ta.reportportal.commons.querygen.query.JoinEntity;
import com.epam.ta.reportportal.commons.querygen.query.QuerySupplier;
Expand All @@ -160,6 +161,7 @@
import com.epam.ta.reportportal.entity.launch.Launch;
import com.epam.ta.reportportal.entity.log.Log;
import com.epam.ta.reportportal.entity.organization.OrganizationFilter;
import com.epam.ta.reportportal.entity.organization.OrganizationUserFilter;
import com.epam.ta.reportportal.entity.project.Project;
import com.epam.ta.reportportal.entity.project.ProjectInfo;
import com.epam.ta.reportportal.entity.user.User;
Expand All @@ -168,7 +170,6 @@
import com.epam.ta.reportportal.jooq.enums.JLaunchModeEnum;
import com.epam.ta.reportportal.jooq.enums.JStatusEnum;
import com.epam.ta.reportportal.jooq.enums.JTestItemTypeEnum;
import com.epam.ta.reportportal.model.ProjectProfile;
import com.google.common.collect.Lists;
import java.sql.Timestamp;
import java.util.ArrayList;
Expand Down Expand Up @@ -1516,7 +1517,7 @@ protected Field<Long> idField() {
new CriteriaHolderBuilder().newBuilder(PROJECT_USER.USER_ID.getName(), PROJECT_USER.USER_ID, Long.class)
.get(),
new CriteriaHolderBuilder().newBuilder(CRITERIA_NAME, PROJECT.NAME, String.class).get(),
new CriteriaHolderBuilder().newBuilder(CRITERIA_NAME, PROJECT.SLUG, String.class).get()
new CriteriaHolderBuilder().newBuilder(CRITERIA_SLUG, PROJECT.SLUG, String.class).get()
)
) {
@Override
Expand Down Expand Up @@ -1573,6 +1574,76 @@ public QuerySupplier wrapQuery(SelectQuery<? extends Record> query, String... ex
protected Field<Long> idField() {
return PROJECT.ID;
}
},

ORGANIZATION_USERS(OrganizationUserFilter.class,
Arrays.asList(
new CriteriaHolderBuilder().newBuilder(CRITERIA_ORG_ID, ORGANIZATION_USER.ORGANIZATION_ID,
Long.class).get(),
new CriteriaHolderBuilder().newBuilder(CRITERIA_FULL_NAME, USERS.FULL_NAME, String.class).get()
)
) {
@Override
public QuerySupplier getQuery() {
SelectQuery<? extends Record> query = DSL.select(selectFields()).getQuery();
addFrom(query);
query.addGroupBy(
ORGANIZATION_USER.USER_ID,
USERS.METADATA,
USERS.EMAIL,
USERS.TYPE,
USERS.ROLE,
USERS.CREATED_AT,
USERS.UPDATED_AT,
USERS.FULL_NAME,
ORGANIZATION_USER.ORGANIZATION_ROLE);
QuerySupplier querySupplier = new QuerySupplier(query);
joinTables(querySupplier);
return querySupplier;
}

@Override
protected Collection<? extends SelectField> selectFields() {
return Lists.newArrayList(DSL.countDistinct(PROJECT.ID).as(PROJECTS_QUANTITY),
ORGANIZATION_USER.USER_ID,
USERS.METADATA,
USERS.EMAIL,
USERS.TYPE,
USERS.ROLE,
USERS.CREATED_AT,
USERS.UPDATED_AT,
USERS.FULL_NAME,
ORGANIZATION_USER.ORGANIZATION_ROLE
);
}

@Override
protected void addFrom(SelectQuery<? extends Record> query) {
query.addFrom(ORGANIZATION_USER);
}

@Override
protected void joinTables(QuerySupplier query) {
query.addJoin(USERS, JoinType.LEFT_OUTER_JOIN, USERS.ID.eq(ORGANIZATION_USER.USER_ID));
query.addJoin(PROJECT_USER, JoinType.LEFT_OUTER_JOIN, PROJECT_USER.USER_ID.eq(ORGANIZATION_USER.USER_ID));
query.addJoin(PROJECT, JoinType.LEFT_OUTER_JOIN, PROJECT.ID.eq(PROJECT_USER.PROJECT_ID)
.and(PROJECT.ORGANIZATION_ID.eq(ORGANIZATION_USER.ORGANIZATION_ID)));
}

@Override
public QuerySupplier wrapQuery(SelectQuery<? extends Record> query) {
throw new UnsupportedOperationException("Operation not supported for OrganizationUserFilter query");
}

@Override
public QuerySupplier wrapQuery(SelectQuery<? extends Record> query, String... excluding) {
throw new UnsupportedOperationException("Operation not supported for OrganizationUserFilter query");
}

@Override
protected Field<Long> idField() {
return ORGANIZATION_USER.ORGANIZATION_ID;
}
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import com.epam.ta.reportportal.dao.FilterableRepository;
import com.epam.ta.reportportal.entity.organization.Organization;
import com.epam.ta.reportportal.model.OrganizationProfile;
import com.epam.reportportal.api.model.OrganizationProfile;
import java.util.Optional;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@

import com.epam.ta.reportportal.commons.querygen.QueryBuilder;
import com.epam.ta.reportportal.commons.querygen.Queryable;
import com.epam.ta.reportportal.dao.custom.ElasticSearchClient;
import com.epam.ta.reportportal.entity.organization.Organization;
import com.epam.ta.reportportal.model.OrganizationProfile;
import com.epam.reportportal.api.model.OrganizationProfile;
import java.util.List;
import java.util.Optional;
import org.jooq.DSLContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2024 EPAM Systems
*
* 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.
*/

package com.epam.ta.reportportal.dao.organization;

import com.epam.reportportal.api.model.OrganizationUserProfile;
import com.epam.ta.reportportal.dao.FilterableRepository;

/**
* Repository interface for searching and filtering organization records.
*
* @author Siarhei Hrabko
*/
public interface OrganizationUsersRepositoryCustom extends FilterableRepository<OrganizationUserProfile> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2024 EPAM Systems
*
* 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.
*/

package com.epam.ta.reportportal.dao.organization;


import static com.epam.ta.reportportal.dao.util.OrganizationMapper.ORGANIZATION_USERS_LIST_FETCHER;

import com.epam.reportportal.api.model.OrganizationUserProfile;
import com.epam.ta.reportportal.commons.querygen.FilterTarget;
import com.epam.ta.reportportal.commons.querygen.QueryBuilder;
import com.epam.ta.reportportal.commons.querygen.Queryable;
import java.util.List;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.SelectQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;

/**
* Repository implementation class for searching and filtering organization records.
*
* @author Siarhei Hrabko
*/
@Repository
public class OrganizationUsersRepositoryCustomImpl implements OrganizationUsersRepositoryCustom {

protected final Logger LOGGER = LoggerFactory.getLogger(
OrganizationUsersRepositoryCustomImpl.class);

@Autowired
private DSLContext dsl;

@Override
public List<OrganizationUserProfile> findByFilter(Queryable filter) {
return ORGANIZATION_USERS_LIST_FETCHER.apply(dsl.fetch(QueryBuilder.newBuilder(filter)
.build()));
}

@Override
public Page<OrganizationUserProfile> findByFilter(Queryable filter, Pageable pageable) {
SelectQuery<? extends Record> query = QueryBuilder.newBuilder(filter).with(pageable).build();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Find organization users query: {}", query);
}
return PageableExecutionUtils.getPage(
ORGANIZATION_USERS_LIST_FETCHER.apply(dsl.fetch(query)),
pageable,
() -> dsl.fetchCount(QueryBuilder.newBuilder(FilterTarget.ORGANIZATION_USERS).build()));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.epam.ta.reportportal.dao.project;

import com.epam.ta.reportportal.commons.querygen.Queryable;
import com.epam.ta.reportportal.model.ProjectProfile;
import com.epam.reportportal.api.model.ProjectProfile;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.epam.ta.reportportal.commons.querygen.FilterTarget;
import com.epam.ta.reportportal.commons.querygen.QueryBuilder;
import com.epam.ta.reportportal.commons.querygen.Queryable;
import com.epam.ta.reportportal.model.ProjectProfile;
import com.epam.reportportal.api.model.ProjectProfile;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,41 @@

package com.epam.ta.reportportal.dao.util;

import static com.epam.ta.reportportal.entity.organization.OrganizationFilter.PROJECTS_QUANTITY;
import static com.epam.ta.reportportal.jooq.Tables.ORGANIZATION;

import static com.epam.ta.reportportal.jooq.Tables.ORGANIZATION_USER;
import static com.epam.ta.reportportal.jooq.tables.JUsers.USERS;

import com.epam.reportportal.api.model.OrganizationInfo.TypeEnum;
import com.epam.reportportal.api.model.OrganizationProfile;
import com.epam.reportportal.api.model.OrganizationRelation;
import com.epam.reportportal.api.model.OrganizationRelationLaunches;
import com.epam.reportportal.api.model.OrganizationRelationLaunchesMeta;
import com.epam.reportportal.api.model.OrganizationRelationProjects;
import com.epam.reportportal.api.model.OrganizationRelationProjectsMeta;
import com.epam.reportportal.api.model.OrganizationRelationUsers;
import com.epam.reportportal.api.model.OrganizationRelationUsersMeta;
import com.epam.reportportal.api.model.OrganizationUserProfile;
import com.epam.reportportal.api.model.OrganizationUserProfile.OrganizationRoleEnum;
import com.epam.reportportal.api.model.OrganizationUserRelation;
import com.epam.reportportal.api.model.OrganizationUserRelationProjects;
import com.epam.reportportal.api.model.OrganizationUserRelationProjectsMeta;
import com.epam.reportportal.api.model.UserAccountInfo.AuthProviderEnum;
import com.epam.reportportal.api.model.UserDetails.InstanceRoleEnum;
import com.epam.ta.reportportal.entity.organization.Organization;
import com.epam.ta.reportportal.entity.organization.OrganizationFilter;
import com.epam.ta.reportportal.model.OrganizationInfo.TypeEnum;
import com.epam.ta.reportportal.model.OrganizationProfile;
import com.epam.ta.reportportal.model.OrganizationRelation;
import com.epam.ta.reportportal.model.OrganizationRelationLaunches;
import com.epam.ta.reportportal.model.OrganizationRelationLaunchesMeta;
import com.epam.ta.reportportal.model.OrganizationRelationProjects;
import com.epam.ta.reportportal.model.OrganizationRelationProjectsMeta;
import com.epam.ta.reportportal.model.OrganizationRelationUsers;
import com.epam.ta.reportportal.model.OrganizationRelationUsersMeta;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.jooq.Record;
import org.jooq.RecordMapper;
import org.jooq.Result;
import org.json.JSONObject;

/**
* Set of record mappers that helps to convert the result of jooq queries into Java objects
Expand Down Expand Up @@ -77,7 +93,7 @@ private OrganizationMapper() {
// set projects
OrganizationRelationProjects rp = new OrganizationRelationProjects();
rp.meta(new OrganizationRelationProjectsMeta()
.count(row.get(OrganizationFilter.PROJECTS_QUANTITY, Integer.class)));
.count(row.get(PROJECTS_QUANTITY, Integer.class)));

// set users
OrganizationRelationUsersMeta usersMeta = new OrganizationRelationUsersMeta()
Expand All @@ -95,4 +111,55 @@ private OrganizationMapper() {
return organization;
};


public static final Function<Result<? extends Record>, List<OrganizationUserProfile>> ORGANIZATION_USERS_LIST_FETCHER = rows -> {
List<OrganizationUserProfile> userProfiles = new ArrayList<>(rows.size());

rows.forEach(row -> {
OrganizationUserProfile organizationUserProfile = new OrganizationUserProfile();

organizationUserProfile.setId(row.get(ORGANIZATION_USER.USER_ID));
organizationUserProfile.setFullName(row.get(USERS.FULL_NAME));
organizationUserProfile.setCreatedAt(row.get(USERS.CREATED_AT, Instant.class));
organizationUserProfile.setUpdatedAt(row.get(USERS.UPDATED_AT, Instant.class));
organizationUserProfile.setInstanceRole(InstanceRoleEnum.fromValue(row.get(USERS.ROLE)));
organizationUserProfile.setOrganizationRole(
OrganizationRoleEnum.fromValue(
row.get(ORGANIZATION_USER.ORGANIZATION_ROLE.getName(), String.class)));
organizationUserProfile.setAuthProvider(AuthProviderEnum.fromValue(row.get(USERS.TYPE)));
organizationUserProfile.setEmail(row.get(USERS.EMAIL));

Optional.ofNullable(row.field(USERS.METADATA))
.ifPresent(meta -> {
// TODO: refactor after switching to jooq 3.19 with jsonb processing support
JSONObject json = new JSONObject(row.get(USERS.METADATA).data());
Long millis = json.optJSONObject("metadata", new JSONObject()).optLong("last_login");
organizationUserProfile.setLastLoginAt(Instant.ofEpochMilli(millis));

});

Optional.ofNullable(row.field(ORGANIZATION.EXTERNAL_ID))
.ifPresent(
extId -> organizationUserProfile.setExternalId(row.get(ORGANIZATION.EXTERNAL_ID)));

// organizationUserProfile.setUuid(row.get(USERS.EXTERNAL_ID, UUID.class));// uncomment later

OrganizationUserRelationProjects projects = new OrganizationUserRelationProjects()
.meta(new OrganizationUserRelationProjectsMeta()
.count(row.get(PROJECTS_QUANTITY, Integer.class))
);

OrganizationUserRelation organizationUserRelation = new OrganizationUserRelation()
.projects(projects);

organizationUserProfile.setRelationships(organizationUserRelation);

userProfiles.add(organizationUserProfile);

});

return userProfiles;
};


}
Loading

0 comments on commit 565a04e

Please sign in to comment.