diff --git a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java index d62e58c9a7..2d2e4160e9 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingDao.java @@ -23,17 +23,8 @@ import org.finos.waltz.data.InlineSelectFieldFactory; import org.finos.waltz.data.JooqUtilities; import org.finos.waltz.data.SelectorUtilities; -import org.finos.waltz.model.EntityKind; -import org.finos.waltz.model.EntityLifecycleStatus; -import org.finos.waltz.model.EntityReference; -import org.finos.waltz.model.IdSelectionOptions; -import org.finos.waltz.model.ImmutableEntityReference; -import org.finos.waltz.model.Operation; -import org.finos.waltz.model.Severity; -import org.finos.waltz.model.measurable_rating.ImmutableMeasurableRating; -import org.finos.waltz.model.measurable_rating.MeasurableRating; -import org.finos.waltz.model.measurable_rating.RemoveMeasurableRatingCommand; -import org.finos.waltz.model.measurable_rating.SaveMeasurableRatingCommand; +import org.finos.waltz.model.*; +import org.finos.waltz.model.measurable_rating.*; import org.finos.waltz.model.tally.ImmutableMeasurableRatingTally; import org.finos.waltz.model.tally.MeasurableRatingTally; import org.finos.waltz.model.tally.Tally; @@ -41,21 +32,7 @@ import org.finos.waltz.schema.tables.EntityHierarchy; import org.finos.waltz.schema.tables.Measurable; import org.finos.waltz.schema.tables.records.MeasurableRatingRecord; -import org.jooq.Condition; -import org.jooq.DSLContext; -import org.jooq.Field; -import org.jooq.Record; -import org.jooq.Record1; -import org.jooq.Record2; -import org.jooq.Record3; -import org.jooq.Record4; -import org.jooq.Record9; -import org.jooq.RecordMapper; -import org.jooq.Select; -import org.jooq.SelectConditionStep; -import org.jooq.SelectHavingStep; -import org.jooq.SelectJoinStep; -import org.jooq.SelectOrderByStep; +import org.jooq.*; import org.jooq.impl.DSL; import org.jooq.lambda.tuple.Tuple2; import org.slf4j.Logger; @@ -80,12 +57,7 @@ import static org.finos.waltz.common.SetUtilities.union; import static org.finos.waltz.common.StringUtilities.firstChar; import static org.finos.waltz.common.StringUtilities.notEmpty; -import static org.finos.waltz.schema.Tables.ALLOCATION; -import static org.finos.waltz.schema.Tables.CHANGE_LOG; -import static org.finos.waltz.schema.Tables.ENTITY_HIERARCHY; -import static org.finos.waltz.schema.Tables.MEASURABLE_CATEGORY; -import static org.finos.waltz.schema.Tables.MEASURABLE_RATING_PLANNED_DECOMMISSION; -import static org.finos.waltz.schema.Tables.USER_ROLE; +import static org.finos.waltz.schema.Tables.*; import static org.finos.waltz.schema.tables.Application.APPLICATION; import static org.finos.waltz.schema.tables.Measurable.MEASURABLE; import static org.finos.waltz.schema.tables.MeasurableRating.MEASURABLE_RATING; @@ -302,7 +274,7 @@ public List statsByAppSelector(Select> sele boolean primaryOnly) { Condition cond = MEASURABLE_CATEGORY.ALLOW_PRIMARY_RATINGS.isFalse() .or(primaryOnly - ? MEASURABLE_RATING.IS_PRIMARY.eq(primaryOnly) + ? MEASURABLE_RATING.IS_PRIMARY.isTrue() : DSL.trueCondition()); return dsl @@ -318,28 +290,6 @@ public List statsByAppSelector(Select> sele } - public List statsForRelatedMeasurable(Select> selector) { - org.finos.waltz.schema.tables.MeasurableRating related = MEASURABLE_RATING.as("related"); - org.finos.waltz.schema.tables.MeasurableRating orig = MEASURABLE_RATING.as("orig"); - - SelectConditionStep> relatedAppIds = DSL - .selectDistinct(orig.ENTITY_ID) - .from(orig) - .where(orig.MEASURABLE_ID.in(selector)) - .and(orig.ENTITY_KIND.eq(EntityKind.APPLICATION.name())); - - return dsl - .select(related.MEASURABLE_ID, - related.RATING, - DSL.count()) - .from(related) - .where(related.ENTITY_ID.in(relatedAppIds)) - .groupBy(related.MEASURABLE_ID, - related.RATING) - .fetch(TO_TALLY_MAPPER); - } - - public int deleteByMeasurableIdSelector(Select> selector) { return dsl .deleteFrom(MEASURABLE_RATING) @@ -817,4 +767,13 @@ public boolean saveRatingDescription(EntityReference entityRef, long measurableI description, username)); } + + + public MeasurableRatingChangeSummary resolveLoggingContextForRatingChange(EntityReference entityRef, + long measurableId, + String desiredRatingCode) { + return MeasurableRatingHelper.resolveLoggingContextForRatingChange(dsl, entityRef, measurableId, desiredRatingCode); + } + + } diff --git a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingHelper.java b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingHelper.java index 5f4b3c3889..0cb3a7b810 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingHelper.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/measurable_rating/MeasurableRatingHelper.java @@ -1,14 +1,26 @@ package org.finos.waltz.data.measurable_rating; +import org.finos.waltz.model.EntityKind; import org.finos.waltz.model.EntityReference; +import org.finos.waltz.model.ImmutableEntityReference; +import org.finos.waltz.model.measurable_rating.ImmutableMeasurableRatingChangeSummary; +import org.finos.waltz.model.measurable_rating.MeasurableRatingChangeSummary; +import org.finos.waltz.schema.tables.*; import org.finos.waltz.schema.tables.records.MeasurableRatingRecord; import org.jooq.Condition; import org.jooq.DSLContext; +import org.jooq.Record; +import org.jooq.SelectConditionStep; import org.jooq.impl.DSL; +import org.jooq.lambda.tuple.Tuple2; import static org.finos.waltz.common.DateTimeUtilities.nowUtcTimestamp; import static org.finos.waltz.data.measurable.MeasurableIdSelectorFactory.allMeasurablesIdsInSameCategory; +import static org.finos.waltz.model.EntityReference.mkRef; +import static org.finos.waltz.schema.Tables.*; +import static org.finos.waltz.schema.tables.Measurable.MEASURABLE; import static org.finos.waltz.schema.tables.MeasurableRating.MEASURABLE_RATING; +import static org.jooq.lambda.tuple.Tuple.tuple; public class MeasurableRatingHelper { @@ -63,12 +75,12 @@ public static boolean saveRatingDescription(DSLContext tx, /** - * @param tx - * @param entityRef - * @param measurableId - * @param ratingCode - * @param username - * @return + * @param tx the dsl context to use + * @param entityRef the entity the rating is against, usually an app + * @param measurableId the measurable being rated against the entity + * @param ratingCode the rating code to use + * @param username who is doing the rating + * @return true iff the item was saved */ public static boolean saveRatingItem(DSLContext tx, EntityReference entityRef, @@ -125,4 +137,82 @@ private static Condition mkPkCondition(EntityReference entityRef, } + /** + * Given and entity, a measurable and a desired rating code this will + * return an object with the following: + * + *
    + *
  • Resolved measurable name and id
  • + *
  • Resolved measurable category name and id
  • + *
  • Maybe a tuple of any current mapping name and code
  • + *
  • Maybe a tuple of the desired mapping name and code
  • + *
+ * + * The main use of this method is to provide additional logging context + * + * @param tx dslContext to issue the query with + * @param entityRef the entity which needs the new rating + * @param measurableId the measurable id for the new rating + * @param desiredRatingCode the rating code for the new rating + * @return resolved names + */ + public static MeasurableRatingChangeSummary resolveLoggingContextForRatingChange(DSLContext tx, + EntityReference entityRef, + long measurableId, + String desiredRatingCode) { + + Measurable m = MEASURABLE.as("m"); + MeasurableCategory mc = MEASURABLE_CATEGORY.as("mc"); + org.finos.waltz.schema.tables.MeasurableRating mr = MEASURABLE_RATING.as("mr"); + RatingScheme rs = RATING_SCHEME.as("rs"); + RatingSchemeItem current = RATING_SCHEME_ITEM.as("current"); + RatingSchemeItem desired = RATING_SCHEME_ITEM.as("desired"); + Application app = APPLICATION.as("app"); + + SelectConditionStep qry = tx + .select(m.NAME, m.ID) + .select(mc.NAME, mc.ID) + .select(app.NAME, app.ID) + .select(current.NAME, current.CODE) + .select(desired.NAME, desired.CODE) + .from(m) + .innerJoin(mc).on(mc.ID.eq(m.MEASURABLE_CATEGORY_ID)) + .innerJoin(rs).on(rs.ID.eq(mc.RATING_SCHEME_ID)) + .innerJoin(app).on(app.ID.eq(entityRef.id())) + .leftJoin(mr).on(mr.MEASURABLE_ID.eq(m.ID) + .and(mr.ENTITY_ID.eq(entityRef.id())) + .and(mr.ENTITY_KIND.eq(entityRef.kind().name()))) + .leftJoin(current).on(current.CODE.eq(mr.RATING) + .and(current.SCHEME_ID.eq(rs.ID))) + .leftJoin(desired).on(desired.CODE.eq(desiredRatingCode) + .and(desired.SCHEME_ID.eq(rs.ID))) + .where(m.ID.eq(measurableId)); + + return qry + .fetchOne(r -> { + String currentCode = r.get(current.CODE); + String currentName = r.get(current.NAME); + String desiredCode = r.get(desired.CODE); + String desiredName = r.get(desired.NAME); + + Tuple2 currentRatingNameAndCode = currentCode == null + ? null + : tuple(currentName, currentCode); + + Tuple2 desiredRatingNameAndCode = desiredCode == null + ? null + : tuple(desiredName, desiredCode); + + return ImmutableMeasurableRatingChangeSummary + .builder() + .measurableRef(mkRef(EntityKind.MEASURABLE, measurableId, r.get(m.NAME))) + .measurableCategoryRef(mkRef(EntityKind.MEASURABLE_CATEGORY, r.get(mc.ID), r.get(mc.NAME))) + .entityRef(ImmutableEntityReference.copyOf(entityRef).withName(r.get(app.NAME))) + .currentRatingNameAndCode(currentRatingNameAndCode) + .desiredRatingNameAndCode(desiredRatingNameAndCode) + .build(); + }); + + } + } diff --git a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/AllocationHarness.java b/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/AllocationHarness.java deleted file mode 100644 index a7ff21671f..0000000000 --- a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/AllocationHarness.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Waltz - Enterprise Architecture - * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project - * See README.md for more information - * - * 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 - * - */ - -package org.finos.waltz.jobs.harness; - -import org.finos.waltz.data.measurable_category.MeasurableCategoryDao; -import org.finos.waltz.model.Criticality; -import org.finos.waltz.model.UserTimestamp; -import org.finos.waltz.model.allocation_scheme.AllocationScheme; -import org.finos.waltz.model.allocation_scheme.ImmutableAllocationScheme; -import org.finos.waltz.model.application.*; -import org.finos.waltz.model.measurable.ImmutableMeasurable; -import org.finos.waltz.model.measurable.Measurable; -import org.finos.waltz.model.measurable_category.MeasurableCategory; -import org.finos.waltz.model.measurable_rating.ImmutableSaveMeasurableRatingCommand; -import org.finos.waltz.model.measurable_rating.SaveMeasurableRatingCommand; -import org.finos.waltz.model.rating.RagRating; -import org.finos.waltz.schema.tables.records.AllocationRecord; -import org.finos.waltz.service.DIConfiguration; -import org.finos.waltz.service.allocation_schemes.AllocationSchemeService; -import org.finos.waltz.service.application.ApplicationService; -import org.finos.waltz.service.measurable.MeasurableService; -import org.finos.waltz.service.measurable_rating.MeasurableRatingService; -import org.jooq.*; -import org.jooq.impl.DSL; -import org.jooq.lambda.tuple.Tuple; -import org.jooq.lambda.tuple.Tuple4; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import java.util.List; - -import static org.finos.waltz.schema.Tables.*; - -@SuppressWarnings("deprecation") -public class AllocationHarness { - - private static final String PROVENANCE = "TEST_DATA_321"; - - public static void main(String[] args) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DIConfiguration.class); - DSLContext dsl = ctx.getBean(DSLContext.class); - - AllocationSchemeService schemesService = ctx.getBean(AllocationSchemeService.class); - MeasurableService measurableService = ctx.getBean(MeasurableService.class); - MeasurableCategoryDao categoryDao = ctx.getBean(MeasurableCategoryDao.class); - MeasurableRatingService ratingService = ctx.getBean(MeasurableRatingService.class); - ApplicationService applicationService = ctx.getBean(ApplicationService.class); - - Tuple4, AllocationScheme> stuff = setup( - dsl, - schemesService, - measurableService, - categoryDao, - applicationService); - - addRating(ratingService, stuff, 0); - addRating(ratingService, stuff, 1); -// addRating(ratingService, stuff, 2); - -// addAllocation(dsl, stuff, 0, 50); - addAllocation(dsl, stuff, 1, 20); - - Long measurableCategory = stuff.v2.id().get(); - - - dumpRatings(dsl, stuff.v4); - dumpAllocs(dsl, stuff.v4); - - doDiff(dsl, measurableCategory); - - System.out.println(ratingService.findByCategory(measurableCategory)); - } - - private static void dumpAllocs(DSLContext dsl, AllocationScheme v4) { - System.out.println("-- ALLOCATIONS ---"); - System.out.println(dsl - .selectFrom(ALLOCATION) - .where(ALLOCATION.ALLOCATION_SCHEME_ID.eq(v4.id().get())) - .fetch()); - } - - private static void dumpRatings(DSLContext dsl, AllocationScheme v4) { - System.out.println("-- RATINGS ---"); - System.out.println(dsl - .select() - .from(MEASURABLE_RATING) - .innerJoin(MEASURABLE).on(MEASURABLE.ID.eq(MEASURABLE_RATING.MEASURABLE_ID)) - .innerJoin(ALLOCATION_SCHEME).on(ALLOCATION_SCHEME.MEASURABLE_CATEGORY_ID.eq(MEASURABLE.MEASURABLE_CATEGORY_ID)) - .where(ALLOCATION_SCHEME.ID.eq(v4.id().get())) - .fetch()); - } - - private static void addAllocation(DSLContext dsl, - Tuple4, AllocationScheme> stuff, - int measurableIdx, - int percentage) { - AllocationRecord allocationRecord = dsl.newRecord(ALLOCATION); - allocationRecord.setAllocationSchemeId(stuff.v4.id().get()); - allocationRecord.setEntityId(stuff.v1.entityReference().id()); - allocationRecord.setEntityKind(stuff.v1.entityReference().kind().name()); - allocationRecord.setAllocationPercentage(percentage); - allocationRecord.setMeasurableId(stuff.v3.get(measurableIdx).id().get()); - allocationRecord.setLastUpdatedBy("admin"); - allocationRecord.setProvenance(PROVENANCE); - - allocationRecord.insert(); - } - - private static void addRating(MeasurableRatingService ratingService, Tuple4, AllocationScheme> stuff, int measurableIdx) { - SaveMeasurableRatingCommand command1 = ImmutableSaveMeasurableRatingCommand.builder() - .entityReference(stuff.v1.entityReference()) - .measurableId(stuff.v3.get(measurableIdx).id().get()) - .provenance(PROVENANCE) - .rating('G') - .lastUpdate(UserTimestamp.mkForUser("admin")) - .build(); - - ratingService.save(command1, false); - } - - private static void doDiff(DSLContext dsl, Long measurableCategory) { - calcAdditions(dsl, measurableCategory); - calcRemovals(dsl, measurableCategory); - } - - private static void calcRemovals(DSLContext dsl, Long measurableCategory) { - Table> obsolete = mkExistingAllocsQry(measurableCategory) - .except(mkExistingRatingsQet(measurableCategory)) - .asTable("obsolete"); - - SelectOnConditionStep qry = dsl - .select(ALLOCATION_SCHEME.ID.as("allocation_scheme_id")) - .select(obsolete.asterisk()) - .select(DSL.val("REMOVE").as("op")) - .from(obsolete) - .innerJoin(ALLOCATION_SCHEME).on(ALLOCATION_SCHEME.MEASURABLE_CATEGORY_ID.eq(measurableCategory)); - - System.out.println("-- REMOVALS --"); - System.out.println(qry.fetch()); - - } - - - private static void calcAdditions(DSLContext dsl, Long measurableCategory) { - Table> additions = mkExistingRatingsQet(measurableCategory) - .except(mkExistingAllocsQry(measurableCategory)) - .asTable("additions"); - - SelectOnConditionStep qry = dsl - .select(ALLOCATION_SCHEME.ID.as("allocation_scheme_id")) - .select(additions.asterisk()) - .select(DSL.val("ADD").as("op")) - .from(additions) - .innerJoin(ALLOCATION_SCHEME).on(ALLOCATION_SCHEME.MEASURABLE_CATEGORY_ID.eq(measurableCategory)); - - System.out.println("-- ADDITIONS --"); - System.out.println(qry.fetch()); - - } - - private static SelectConditionStep> mkExistingAllocsQry(Long categoryId) { - return DSL - .select(ALLOCATION.MEASURABLE_ID, - ALLOCATION.ENTITY_ID, - ALLOCATION.ENTITY_KIND) - .from(ALLOCATION) - .innerJoin(ALLOCATION_SCHEME).on(ALLOCATION_SCHEME.ID.eq(ALLOCATION.ALLOCATION_SCHEME_ID)) - .where(ALLOCATION_SCHEME.MEASURABLE_CATEGORY_ID.eq(categoryId)); - } - - - private static Tuple4, AllocationScheme> setup(DSLContext dsl, - AllocationSchemeService schemesService, - MeasurableService measurableService, - MeasurableCategoryDao categoryDao, - ApplicationService applicationService) { - deleteAll(dsl); - Application app = mkApp(dsl, applicationService); - MeasurableCategory category = mkCategory(dsl, categoryDao); - List measurables = mkMeasurables(measurableService, category); - AllocationScheme scheme = mkScheme(schemesService, category); - - return Tuple.tuple(app,category,measurables,scheme); - } - - - private static SelectConditionStep> mkExistingRatingsQet(Long measurableCategory) { - return DSL - .select(MEASURABLE_RATING.MEASURABLE_ID, - MEASURABLE_RATING.ENTITY_ID, - MEASURABLE_RATING.ENTITY_KIND) - .from(MEASURABLE_RATING) - .innerJoin(MEASURABLE).on(MEASURABLE.ID.eq(MEASURABLE_RATING.MEASURABLE_ID)) - .where(MEASURABLE.MEASURABLE_CATEGORY_ID.eq(measurableCategory)); - } - - - private static AllocationScheme mkScheme(AllocationSchemeService schemeService, MeasurableCategory category) { - AllocationScheme scheme = ImmutableAllocationScheme.builder() - .description(PROVENANCE) - .name("TEST_SCHEME") - .measurableCategoryId(category.id().get()) - .build(); - - long id = schemeService.create(scheme); - - return schemeService.getById(id); - } - - - private static List mkMeasurables(MeasurableService measurableService, MeasurableCategory category) { - Measurable m = ImmutableMeasurable.builder() - .name("z") - .categoryId(category.id().get()) - .concrete(true) - .provenance(PROVENANCE) - .lastUpdatedBy("admin") - .build(); - - measurableService.create(ImmutableMeasurable.copyOf(m).withName("A"), "admin"); - measurableService.create(ImmutableMeasurable.copyOf(m).withName("B"), "admin"); - measurableService.create(ImmutableMeasurable.copyOf(m).withName("C"), "admin"); - - return measurableService.findByCategoryId(category.id().get()); - } - - private static MeasurableCategory mkCategory(DSLContext dsl, MeasurableCategoryDao categoryDao) { - Long categoryId = dsl.insertInto(MEASURABLE_CATEGORY) - .set(MEASURABLE_CATEGORY.NAME, "Test") - .set(MEASURABLE_CATEGORY.RATING_SCHEME_ID, 1L) - .set(MEASURABLE_CATEGORY.LAST_UPDATED_BY, "admin") - .set(MEASURABLE_CATEGORY.DESCRIPTION, PROVENANCE) - .set(MEASURABLE_CATEGORY.EXTERNAL_ID, PROVENANCE) - .returning(MEASURABLE_CATEGORY.ID) - .fetchOne() - .getId(); - - return categoryDao.getById(categoryId); - } - - - private static Application mkApp(DSLContext dsl, ApplicationService applicationService) { - AppRegistrationRequest req = ImmutableAppRegistrationRequest.builder() - .name("TEST APP") - .organisationalUnitId(10L) - .businessCriticality(Criticality.UNKNOWN) - .applicationKind(ApplicationKind.EUC) - .lifecyclePhase(LifecyclePhase.PRODUCTION) - .overallRating(RagRating.G) - .build(); - AppRegistrationResponse resp = applicationService.registerApp(req, "admin"); - dsl.update(APPLICATION) - .set(APPLICATION.PROVENANCE, PROVENANCE) - .where(APPLICATION.ID.eq(resp.id().get())) - .execute(); - - return applicationService.getById(resp.id().get()); - } - - - private static void deleteAll(DSLContext dsl) { - dsl.deleteFrom(APPLICATION).where(APPLICATION.PROVENANCE.eq(PROVENANCE)).execute(); - dsl.deleteFrom(MEASURABLE).where(MEASURABLE.PROVENANCE.eq(PROVENANCE)).execute(); - dsl.deleteFrom(MEASURABLE_CATEGORY).where(MEASURABLE_CATEGORY.EXTERNAL_ID.eq(PROVENANCE)).execute(); - dsl.deleteFrom(ALLOCATION_SCHEME).where(ALLOCATION_SCHEME.DESCRIPTION.eq(PROVENANCE)).execute(); - dsl.deleteFrom(ALLOCATION).where(ALLOCATION.PROVENANCE.eq(PROVENANCE)).execute(); - } -} diff --git a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/MeasurableRatingHarness.java b/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/MeasurableRatingHarness.java index bf390f37ce..5b1a7ed31e 100644 --- a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/MeasurableRatingHarness.java +++ b/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/MeasurableRatingHarness.java @@ -18,24 +18,14 @@ package org.finos.waltz.jobs.harness; -import org.finos.waltz.data.measurable.MeasurableIdSelectorFactory; import org.finos.waltz.data.measurable_rating.MeasurableRatingDao; -import org.finos.waltz.model.EntityReference; -import org.finos.waltz.model.IdSelectionOptions; -import org.finos.waltz.model.tally.MeasurableRatingTally; import org.finos.waltz.model.tally.Tally; import org.finos.waltz.service.DIConfiguration; -import org.jooq.Record1; -import org.jooq.Select; import org.jooq.tools.json.ParseException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.util.List; -import static org.finos.waltz.model.EntityKind.MEASURABLE; -import static org.finos.waltz.model.EntityReference.mkRef; -import static org.finos.waltz.model.HierarchyQueryScope.CHILDREN; - public class MeasurableRatingHarness { @@ -44,20 +34,6 @@ public static void main(String[] args) throws ParseException { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DIConfiguration.class); MeasurableRatingDao measurableRatingDao = ctx.getBean(MeasurableRatingDao.class); - MeasurableIdSelectorFactory measurableIdSelectorFactory = new MeasurableIdSelectorFactory(); - - EntityReference direct = mkRef(MEASURABLE, 18310); - EntityReference indirect = mkRef(MEASURABLE, 18064); - - IdSelectionOptions directOpts = IdSelectionOptions.mkOpts(direct, CHILDREN); - IdSelectionOptions indirectOpts = IdSelectionOptions.mkOpts(indirect, CHILDREN); - - Select> directSelector = measurableIdSelectorFactory.apply(directOpts); - Select> indirectSelector = measurableIdSelectorFactory.apply(indirectOpts); - - List directTallies = measurableRatingDao.statsForRelatedMeasurable(directSelector); - List indirectTallies = measurableRatingDao.statsForRelatedMeasurable(indirectSelector); - List> tallies = measurableRatingDao.tallyByMeasurableCategoryId(1L); System.out.println(tallies); diff --git a/waltz-model/src/main/java/org/finos/waltz/model/measurable_rating/MeasurableRatingChangeSummary.java b/waltz-model/src/main/java/org/finos/waltz/model/measurable_rating/MeasurableRatingChangeSummary.java new file mode 100644 index 0000000000..5ef49833aa --- /dev/null +++ b/waltz-model/src/main/java/org/finos/waltz/model/measurable_rating/MeasurableRatingChangeSummary.java @@ -0,0 +1,27 @@ +package org.finos.waltz.model.measurable_rating; + +import org.finos.waltz.model.EntityReference; +import org.finos.waltz.model.Nullable; +import org.immutables.value.Value; +import org.jooq.lambda.tuple.Tuple2; + +/** + * the purpose of this class is to provide information that can be used + * to create detail audit change-log messages + */ +@Value.Immutable +public abstract class MeasurableRatingChangeSummary { + + public abstract EntityReference entityRef(); + + public abstract EntityReference measurableRef(); + + public abstract EntityReference measurableCategoryRef(); + + @Nullable + public abstract Tuple2 currentRatingNameAndCode(); + + @Nullable + public abstract Tuple2 desiredRatingNameAndCode(); + +} diff --git a/waltz-ng/client/measurable-rating/services/measurable-rating-store.js b/waltz-ng/client/measurable-rating/services/measurable-rating-store.js index 4ea95672e7..5a8479b944 100644 --- a/waltz-ng/client/measurable-rating/services/measurable-rating-store.js +++ b/waltz-ng/client/measurable-rating/services/measurable-rating-store.js @@ -21,7 +21,6 @@ import {checkIsEntityRef, checkIsIdSelector} from "../../common/checks"; function store($http, baseApiUrl) { const baseUrl = `${baseApiUrl}/measurable-rating`; - const viewBaseUrl = `${baseApiUrl}/measurable-rating-view`; const findForEntityReference = (ref) => { checkIsEntityRef(ref); diff --git a/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java b/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java index 0a70ff3e8a..5556e60f33 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/measurable_rating/MeasurableRatingService.java @@ -18,9 +18,6 @@ package org.finos.waltz.service.measurable_rating; -import org.finos.waltz.model.measurable_rating.MeasurableRatingStatParams; -import org.finos.waltz.service.changelog.ChangeLogService; -import org.finos.waltz.service.rating_scheme.RatingSchemeService; import org.finos.waltz.common.DateTimeUtilities; import org.finos.waltz.data.EntityReferenceNameResolver; import org.finos.waltz.data.application.ApplicationIdSelectorFactory; @@ -28,19 +25,29 @@ import org.finos.waltz.data.measurable.MeasurableIdSelectorFactory; import org.finos.waltz.data.measurable_category.MeasurableCategoryDao; import org.finos.waltz.data.measurable_rating.MeasurableRatingDao; -import org.finos.waltz.model.*; +import org.finos.waltz.model.EntityKind; +import org.finos.waltz.model.EntityReference; +import org.finos.waltz.model.IdSelectionOptions; +import org.finos.waltz.model.Operation; +import org.finos.waltz.model.Severity; +import org.finos.waltz.model.UserTimestamp; import org.finos.waltz.model.changelog.ImmutableChangeLog; import org.finos.waltz.model.measurable.Measurable; import org.finos.waltz.model.measurable_category.MeasurableCategory; import org.finos.waltz.model.measurable_rating.MeasurableRating; +import org.finos.waltz.model.measurable_rating.MeasurableRatingChangeSummary; import org.finos.waltz.model.measurable_rating.MeasurableRatingCommand; +import org.finos.waltz.model.measurable_rating.MeasurableRatingStatParams; import org.finos.waltz.model.measurable_rating.RemoveMeasurableRatingCommand; import org.finos.waltz.model.measurable_rating.SaveMeasurableRatingCommand; import org.finos.waltz.model.rating.RatingSchemeItem; import org.finos.waltz.model.tally.MeasurableRatingTally; import org.finos.waltz.model.tally.Tally; +import org.finos.waltz.service.changelog.ChangeLogService; +import org.finos.waltz.service.rating_scheme.RatingSchemeService; import org.jooq.Record1; import org.jooq.Select; +import org.jooq.lambda.tuple.Tuple2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -106,42 +113,13 @@ public Collection findByAppIdSelector(IdSelectionOptions optio return measurableRatingDao.findByApplicationIdSelector(selector); } - // -- WRITE - - public Collection save(SaveMeasurableRatingCommand command, boolean ignoreReadOnly) { - checkNotNull(command, "command cannot be null"); - - checkRatingIsAllowable(command); - - Measurable measurable = measurableDao.getById(command.measurableId()); - checkNotNull(measurable, format("Unknown measurable with id: %d", command.measurableId())); - checkTrue(measurable.concrete(), "Cannot rate against an abstract measurable"); - - Operation operationThatWasPerformed = measurableRatingDao.save(command, false); - - String entityName = getEntityName(command); - - String previousRatingMessage = command.previousRating().isPresent() - ? "from " + command.previousRating().get() : ""; - - writeChangeLogEntry( - command, - format("Saved: %s with a rating of: %s %s for %s", - measurable.name(), - command.rating(), - previousRatingMessage, - entityName), - format("Saved: %s has assigned %s with a rating of: %s %s", - entityName, - measurable.name(), - command.rating(), - previousRatingMessage), - operationThatWasPerformed); - - return findForEntity(command.entityReference()); + public Collection findByCategory(long id) { + return measurableRatingDao.findByCategory(id); } + // -- WRITE + /** * Removes all ratings for the given entity where the associated * measurable belongs to the given category. @@ -183,84 +161,154 @@ public Collection remove(RemoveMeasurableRatingCommand command String entityName = getEntityName(command); writeChangeLogEntry( - command, + command.entityReference(), + measurable.entityReference(), format("Removed: %s for %s", measurable.name(), entityName), format("Removed: %s for %s", entityName, measurable.name()), - Operation.REMOVE); + Operation.REMOVE, + command.lastUpdate()); } return findForEntity(command.entityReference()); } - public List> tallyByMeasurableCategoryId(long categoryId) { - return measurableRatingDao.tallyByMeasurableCategoryId(categoryId); + public int deleteByMeasurableIdSelector(IdSelectionOptions selectionOptions) { + Select> selector = measurableIdSelectorFactory + .apply(selectionOptions); + return measurableRatingDao + .deleteByMeasurableIdSelector(selector); } - public Collection statsForRelatedMeasurable(IdSelectionOptions options) { - Select> selector = measurableIdSelectorFactory.apply(options); - return measurableRatingDao.statsForRelatedMeasurable(selector); - } + public boolean saveRatingItem(EntityReference entityRef, + long measurableId, + String ratingCode, + String username) { + long categoryId = measurableDao.getById(measurableId).categoryId(); + checkRatingIsAllowable(categoryId, entityRef, ratingCode); - public List statsByAppSelector(MeasurableRatingStatParams params) { - checkNotNull(params, "params cannot be null"); - Select> selector = applicationIdSelectorFactory.apply(params.options()); - return measurableRatingDao.statsByAppSelector( - selector, - params.showPrimaryOnly()); + MeasurableRatingChangeSummary loggingInfo = measurableRatingDao.resolveLoggingContextForRatingChange( + entityRef, + measurableId, + ratingCode); + + boolean rc = measurableRatingDao.saveRatingItem( + entityRef, + measurableId, + ratingCode, + username); + + if (rc) { + writeChangeLogEntry( + entityRef, + loggingInfo.measurableRef(), + format("Saving rating for: %s, in category: %s, new value: %s, old value: %s", + prettyRef(loggingInfo.measurableRef()), + prettyRef(loggingInfo.measurableCategoryRef()), + prettyRating(loggingInfo.desiredRatingNameAndCode()), + prettyRating(loggingInfo.currentRatingNameAndCode())), + format("Saving rating for application %s, new value: %s, old value: %s", + prettyRef(loggingInfo.entityRef()), + prettyRating(loggingInfo.desiredRatingNameAndCode()), + prettyRating(loggingInfo.currentRatingNameAndCode())), + loggingInfo.currentRatingNameAndCode() == null + ? Operation.ADD + : Operation.UPDATE, + UserTimestamp.mkForUser(username)); + } + + return rc; } - public boolean hasImplicitlyRelatedMeasurables(long measurableId, IdSelectionOptions options) { - Select> selector = applicationIdSelectorFactory.apply(options); - return measurableRatingDao.hasImplicitlyRelatedMeasurables(measurableId, selector); + public boolean saveRatingIsPrimary(EntityReference entityRef, + long measurableId, + boolean isPrimary, + String username) { + + MeasurableRatingChangeSummary loggingInfo = measurableRatingDao.resolveLoggingContextForRatingChange( + entityRef, + measurableId, + null); + + boolean rc = measurableRatingDao.saveRatingIsPrimary( + entityRef, + measurableId, + isPrimary, + username); + + if (rc) { + writeChangeLogEntry( + entityRef, + loggingInfo.measurableRef(), + format("Setting primary rating flag for: %s, in category: %s", + prettyRef(loggingInfo.measurableRef()), + prettyRef(loggingInfo.measurableCategoryRef())), + format("Setting primary flag for application: %s", + prettyRef(loggingInfo.entityRef())), + Operation.UPDATE, + UserTimestamp.mkForUser(username)); + } + + return rc; } - // -- HELPERS -- + public boolean saveRatingDescription(EntityReference entityRef, + long measurableId, + String description, + String username) { - private void writeChangeLogEntry(MeasurableRatingCommand command, - String message1, - String message2, - Operation operation) { + MeasurableRatingChangeSummary loggingInfo = measurableRatingDao.resolveLoggingContextForRatingChange( + entityRef, + measurableId, + null); - changeLogService.write(ImmutableChangeLog.builder() - .message(message1) - .parentReference(command.entityReference()) - .userId(command.lastUpdate().by()) - .createdAt(command.lastUpdate().at()) - .severity(Severity.INFORMATION) - .childKind(EntityKind.MEASURABLE) - .operation(operation) - .build()); + boolean rc = measurableRatingDao.saveRatingDescription(entityRef, measurableId, description, username); - changeLogService.write(ImmutableChangeLog.builder() - .message(message2) - .parentReference(EntityReference.mkRef(EntityKind.MEASURABLE, command.measurableId())) - .userId(command.lastUpdate().by()) - .createdAt(command.lastUpdate().at()) - .severity(Severity.INFORMATION) - .childKind(command.entityReference().kind()) - .operation(operation) - .build()); + if (rc) { + writeChangeLogEntry( + entityRef, + loggingInfo.measurableRef(), + format("Updating description for rating: %s, in category: %s, new value: %s", + prettyRef(loggingInfo.measurableRef()), + prettyRef(loggingInfo.measurableCategoryRef()), + description), + format("Updated rating description for application: %s, new value: %s", + prettyRef(loggingInfo.entityRef()), + description), + Operation.UPDATE, + UserTimestamp.mkForUser(username)); + } + + return rc; } - public Collection findByCategory(long id) { - return measurableRatingDao.findByCategory(id); + // STATS + + public List> tallyByMeasurableCategoryId(long categoryId) { + return measurableRatingDao.tallyByMeasurableCategoryId(categoryId); } - public int deleteByMeasurableIdSelector(IdSelectionOptions selectionOptions) { - Select> selector = measurableIdSelectorFactory - .apply(selectionOptions); - return measurableRatingDao - .deleteByMeasurableIdSelector(selector); + public List statsByAppSelector(MeasurableRatingStatParams params) { + checkNotNull(params, "params cannot be null"); + Select> selector = applicationIdSelectorFactory.apply(params.options()); + return measurableRatingDao.statsByAppSelector( + selector, + params.showPrimaryOnly()); + } + + + public boolean hasImplicitlyRelatedMeasurables(long measurableId, IdSelectionOptions options) { + Select> selector = applicationIdSelectorFactory.apply(options); + return measurableRatingDao.hasImplicitlyRelatedMeasurables(measurableId, selector); } @@ -277,64 +325,64 @@ private String getEntityName(MeasurableRatingCommand command) { } + @Deprecated public boolean checkRatingExists(SaveMeasurableRatingCommand command) { return measurableRatingDao.checkRatingExists(command); } + public void migrateRatings(Long measurableId, Long targetMeasurableId, String userId) { measurableRatingDao.migrateRatings(measurableId, targetMeasurableId, userId); } + public int getSharedRatingsCount(Long measurableId, Long targetMeasurableId) { return measurableRatingDao.getSharedRatingsCount(measurableId, targetMeasurableId); } + public int getSharedDecommsCount(Long measurableId, Long targetMeasurableId) { return measurableRatingDao.getSharedDecommsCount(measurableId, targetMeasurableId); } - public boolean saveRatingItem(EntityReference entityRef, - long measurableId, - String ratingCode, - String username) { - long categoryId = measurableDao.getById(measurableId).categoryId(); - checkRatingIsAllowable(categoryId, entityRef, ratingCode); - return measurableRatingDao.saveRatingItem(entityRef, measurableId, ratingCode, username); - } - - public boolean saveRatingIsPrimary(EntityReference entityRef, - long measurableId, - boolean isPrimary, - String username) { - return measurableRatingDao.saveRatingIsPrimary(entityRef, measurableId, isPrimary, username); - } - - - public boolean saveRatingDescription(EntityReference entityRef, - long measurableId, - String description, - String username) { - return measurableRatingDao.saveRatingDescription(entityRef, measurableId, description, username); - } // ---- HELPER ----- - private void checkRatingIsAllowable(SaveMeasurableRatingCommand command) { + private void writeChangeLogEntry(EntityReference ratedEntity, + EntityReference measurable, + String message1, + String message2, + Operation operation, + UserTimestamp userTimestamp) { - long measurableCategory = measurableDao.getById(command.measurableId()).categoryId(); - EntityReference entityReference = command.entityReference(); - String ratingCode = Character.toString(command.rating()); + changeLogService.write(ImmutableChangeLog.builder() + .message(message1) + .parentReference(ratedEntity) + .userId(userTimestamp.by()) + .createdAt(userTimestamp.at()) + .severity(Severity.INFORMATION) + .childKind(EntityKind.MEASURABLE) + .operation(operation) + .build()); - checkRatingIsAllowable(measurableCategory, entityReference, ratingCode); + changeLogService.write(ImmutableChangeLog.builder() + .message(message2) + .parentReference(measurable) + .userId(userTimestamp.by()) + .createdAt(userTimestamp.at()) + .severity(Severity.INFORMATION) + .childKind(ratedEntity.kind()) + .operation(operation) + .build()); } /** * Checks * - * @param measurableCategory - * @param entityReference - * @param ratingCode + * @param measurableCategory category to check against, indirectly gives the rating scheme + * @param entityReference the entity the rating is against + * @param ratingCode the rating code that is being checked */ private void checkRatingIsAllowable(long measurableCategory, EntityReference entityReference, @@ -351,4 +399,19 @@ private void checkRatingIsAllowable(long measurableCategory, } + private String prettyRef(EntityReference ref) { + return ref == null + ? "-" + : format("%s [%d]", ref.name().orElse("?"), ref.id()); + } + + + private String prettyRating(Tuple2 nameAndCode) { + return nameAndCode == null + ? "-" + : format("%s [%s]", nameAndCode.v1, nameAndCode.v2); + } + + + } diff --git a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/MeasurableRatingEndpoint.java b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/MeasurableRatingEndpoint.java index 84b15a5e75..5aa815b717 100644 --- a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/MeasurableRatingEndpoint.java +++ b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/MeasurableRatingEndpoint.java @@ -24,16 +24,12 @@ import org.finos.waltz.model.Operation; import org.finos.waltz.model.UserTimestamp; import org.finos.waltz.model.measurable_rating.ImmutableRemoveMeasurableRatingCommand; -import org.finos.waltz.model.measurable_rating.ImmutableSaveMeasurableRatingCommand; import org.finos.waltz.model.measurable_rating.MeasurableRating; import org.finos.waltz.model.measurable_rating.MeasurableRatingStatParams; import org.finos.waltz.model.measurable_rating.RemoveMeasurableRatingCommand; -import org.finos.waltz.model.measurable_rating.SaveMeasurableRatingCommand; import org.finos.waltz.model.tally.MeasurableRatingTally; import org.finos.waltz.model.tally.Tally; -import org.finos.waltz.service.measurable.MeasurableService; import org.finos.waltz.service.measurable_rating.MeasurableRatingService; -import org.finos.waltz.service.permission.PermissionGroupService; import org.finos.waltz.service.permission.permission_checker.MeasurableRatingPermissionChecker; import org.finos.waltz.service.user.UserRoleService; import org.finos.waltz.web.DatumRoute; @@ -46,26 +42,14 @@ import java.io.IOException; import java.util.Collection; -import java.util.Map; import java.util.Set; import static org.finos.waltz.common.Checks.checkNotNull; import static org.finos.waltz.common.SetUtilities.asSet; -import static org.finos.waltz.common.StringUtilities.firstChar; import static org.finos.waltz.model.EntityKind.MEASURABLE_RATING; import static org.finos.waltz.model.EntityReference.mkRef; -import static org.finos.waltz.web.WebUtilities.getEntityReference; -import static org.finos.waltz.web.WebUtilities.getId; -import static org.finos.waltz.web.WebUtilities.getLong; -import static org.finos.waltz.web.WebUtilities.getUsername; -import static org.finos.waltz.web.WebUtilities.mkPath; -import static org.finos.waltz.web.WebUtilities.readBody; -import static org.finos.waltz.web.WebUtilities.readIdSelectionOptionsFromBody; -import static org.finos.waltz.web.WebUtilities.requireRole; -import static org.finos.waltz.web.endpoints.EndpointUtilities.deleteForList; -import static org.finos.waltz.web.endpoints.EndpointUtilities.getForList; -import static org.finos.waltz.web.endpoints.EndpointUtilities.postForDatum; -import static org.finos.waltz.web.endpoints.EndpointUtilities.postForList; +import static org.finos.waltz.web.WebUtilities.*; +import static org.finos.waltz.web.endpoints.EndpointUtilities.*; @Service public class MeasurableRatingEndpoint implements Endpoint { @@ -76,24 +60,18 @@ public class MeasurableRatingEndpoint implements Endpoint { private final MeasurableRatingService measurableRatingService; private final MeasurableRatingPermissionChecker measurableRatingPermissionChecker; private final UserRoleService userRoleService; - private final PermissionGroupService permissionGroupService; @Autowired public MeasurableRatingEndpoint(MeasurableRatingService measurableRatingService, MeasurableRatingPermissionChecker measurableRatingPermissionChecker, - MeasurableService measurableService, - UserRoleService userRoleService, - PermissionGroupService permissionGroupService) { + UserRoleService userRoleService) { checkNotNull(measurableRatingService, "measurableRatingService cannot be null"); - checkNotNull(measurableRatingService, "measurableService cannot be null"); checkNotNull(userRoleService, "userRoleService cannot be null"); - checkNotNull(permissionGroupService, "permissionGroupService cannot be null"); checkNotNull(measurableRatingPermissionChecker, "measurableRatingPermissionChecker cannot be null"); this.measurableRatingService = measurableRatingService; - this.permissionGroupService = permissionGroupService; this.measurableRatingPermissionChecker = measurableRatingPermissionChecker; this.userRoleService = userRoleService; } @@ -142,7 +120,6 @@ public void register() { postForList(findByMeasurableSelectorPath, findByMeasurableSelectorRoute); postForList(findByAppSelectorPath, findByAppSelectorRoute); getForList(findByCategoryPath, findByCategoryRoute); - postForList(modifyMeasurableForEntityPath, this::saveRoute); deleteForList(modifyMeasurableForEntityPath, this::removeRoute); deleteForList(modifyCategoryForEntityPath, this::removeCategoryRoute); getForList(countByMeasurableCategoryPath, countByMeasurableCategoryRoute); @@ -207,19 +184,6 @@ private Collection removeCategoryRoute(Request request, Respon } - private Collection saveRoute(Request request, Response z) throws IOException, InsufficientPrivelegeException { - SaveMeasurableRatingCommand command = mkCommand(request); - - Operation operation = measurableRatingService.checkRatingExists(command) - ? Operation.UPDATE - : Operation.ADD; - - checkHasPermissionForThisOperation(command.entityReference(), command.measurableId(), asSet(operation), getUsername(request)); - - return measurableRatingService.save(command, false); - } - - private Collection removeRoute(Request request, Response z) throws IOException, InsufficientPrivelegeException { long measurableId = getLong(request, "measurableId"); String username = getUsername(request); @@ -237,23 +201,6 @@ private Collection removeRoute(Request request, Response z) th } - private SaveMeasurableRatingCommand mkCommand(Request request) throws IOException { - String username = getUsername(request); - - Map body = readBody(request, Map.class); - - return ImmutableSaveMeasurableRatingCommand.builder() - .entityReference(getEntityReference(request)) - .measurableId(getLong(request, "measurableId")) - .rating(firstChar(body.getOrDefault("rating", "Z"), 'Z')) - .previousRating(firstChar(body.getOrDefault("previousRating", ""))) - .description(body.getOrDefault("description", "")) - .lastUpdate(UserTimestamp.mkForUser(username)) - .provenance("waltz") - .build(); - } - - private void checkHasPermissionForThisOperation(EntityReference parentRef, Long measurableId, Set operations,