Skip to content

Commit

Permalink
OD-18799 feat: extend of subjects only if preference was set
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitars committed Mar 29, 2024
1 parent b7e4d18 commit 2e0b858
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ class TagFunctions {
.collectEntries { [(it[0]): it[1]] }
}

static SpecialTagDTO toRestSpecial(NodeSpecialType specialType, List<Tag> childTags){
static SpecialTagDTO toRestSpecial(NodeSpecialType specialType, List<Tag> childTags) {
return new SpecialTagDTO().with { dto ->
dto.specialType = SpecialTagTypeDTO.fromValue(specialType.displayName)
dto.childTags = childTags.sort { it.weight }.collect {toRestTag(it)}
dto.childTags = childTags.sort { it.weight }.collect { toRestTag(it) }
dto
}
}
Expand Down Expand Up @@ -114,7 +114,7 @@ class TagFunctions {
String errorMessage = 'Tag group can not be deleted'
switch (dbTag.specialType) {
case NodeSpecialType.SUBJECTS:
errorMessage += ' This tag group represents the categories of courses/products on your web site and cannot be deleted.'
errorMessage += ' This entity represents the categories of courses/products on your web site and cannot be deleted.'
break
case NodeSpecialType.TERMS:
errorMessage += ' This tag group represents the categories of classes on your web site and cannot be deleted.'
Expand All @@ -134,7 +134,7 @@ class TagFunctions {
null
}

static ValidationErrorDTO validateForSave(ObjectContext context, TagDTO tag) {
static ValidationErrorDTO validateForSave(ObjectContext context, TagDTO tag, boolean subjectsAsEntity = false) {

ValidationErrorDTO error = validateTag(tag)
if (error) {
Expand All @@ -150,6 +150,12 @@ class TagFunctions {
return new ValidationErrorDTO(tag.id?.toString(), 'name', 'Name should be unique.')
}

if (subjectsAsEntity) {
error = validateSubjectAsEntity(tag, dbTag)
if (error)
return error
}

Set<String> notValidNames = new HashSet<>()
validateNamesOfNewTag(tag, notValidNames)
if (notValidNames.size() > 0) {
Expand Down Expand Up @@ -438,4 +444,18 @@ class TagFunctions {
}
return null
}


private static ValidationErrorDTO validateSubjectAsEntity(TagDTO tagDTO, Tag tag) {
if (tagDTO.requirements.find { !it.id })
return new ValidationErrorDTO(null, 'subjects', "You cannot update requirement for subject entity")

if (tagDTO.requirements.id.find { !tag.tagRequirements.id.contains(it) }) {
return new ValidationErrorDTO(null, 'subjects', "You cannot add new requirement for subject entity")
}

if (tag.tagRequirements.id.find { !tagDTO.requirements.id.contains(it) }) {
return new ValidationErrorDTO(null, 'subjects', "You cannot remove requirement for subject entity")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ish.oncourse.server.api.v1.model.ValidationErrorDTO
import ish.oncourse.server.api.v1.service.TagApi
import ish.oncourse.server.cayenne.Tag
import ish.oncourse.server.cayenne.glue.TaggableCayenneDataObject
import ish.persistence.CommonPreferenceController
import org.apache.cayenne.ObjectContext
import org.apache.cayenne.query.ObjectSelect
import org.apache.cayenne.query.SelectById
Expand All @@ -45,6 +46,9 @@ class TagApiImpl implements TagApi {
@Inject
private SpecialTagsApiService specialTagsApiService

@Inject
private CommonPreferenceController preferenceController

@Override
List<TagDTO> getChecklists(String entityName, Long id) {
def taggableClassesForEntity = taggableClassesFor(entityName)
Expand Down Expand Up @@ -129,7 +133,7 @@ class TagApiImpl implements TagApi {
Tag dbTag = CayenneFunctions
.getRecordById(context, Tag, id, tagGroupPrefetch)

ValidationErrorDTO error = validateForSave(context, tag)
ValidationErrorDTO error = validateForSave(context, tag, preferenceController.extendedSearchTypesAllowed)
if (error) {
context.rollbackChanges()
throw new ClientErrorException(Response.status(Response.Status.BAD_REQUEST).entity(error).build())
Expand Down
209 changes: 128 additions & 81 deletions server/src/main/java/ish/oncourse/entity/services/TagService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,122 +12,169 @@

import ish.common.types.NodeSpecialType;
import ish.oncourse.cayenne.Taggable;
import ish.oncourse.server.cayenne.Course;
import ish.oncourse.server.cayenne.Tag;
import ish.oncourse.server.api.v1.function.TagRequirementFunctions;
import ish.oncourse.server.cayenne.*;
import org.apache.cayenne.CayenneDataObject;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.query.ObjectSelect;
import org.apache.cayenne.query.Ordering;
import org.apache.cayenne.query.SortOrder;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
*
*/
public class TagService {

/**
* @return List of Tags in subject category, alphabetically sorted.
*/
public List<? extends Tag> getSubjectTagsForCourse(Course course) {
List<Tag> result = new ArrayList<>();
private static final List<Class<? extends CayenneDataObject>> SUBJECT_ENTITIES = List.of(Course.class,
ArticleProduct.class, VoucherProduct.class, MembershipProduct.class);

for (Tag n : course.getTags()) {
if (NodeSpecialType.SUBJECTS.equals(n.getRoot().getSpecialType())) {
result.add(n);
}
}
Ordering o = new Ordering(Tag.NAME_KEY, SortOrder.ASCENDING);
o.orderList(result);
return result;
}
/**
* @return List of Tags in subject category, alphabetically sorted.
*/
public List<? extends Tag> getSubjectTagsForCourse(Course course) {
List<Tag> result = new ArrayList<>();

for (Tag n : course.getTags()) {
if (NodeSpecialType.SUBJECTS.equals(n.getRoot().getSpecialType())) {
result.add(n);
}
}
Ordering o = new Ordering(Tag.NAME_KEY, SortOrder.ASCENDING);
o.orderList(result);
return result;
}

/**
* Check to see whether this object has this tag.
*
* @param taggable the object that can have related tags
* @param path the tag name or the full path to the tag
* @param taggable the object that can have related tags
* @param path the tag name or the full path to the tag
* @param isSearchWithChildren define if method will be searching for tag in parents of taggable's tags
* @return
*/
public boolean hasTag(Taggable taggable, String path, boolean isSearchWithChildren) {
public boolean hasTag(Taggable taggable, String path, boolean isSearchWithChildren) {

path = trimPath(path);
path = trimPath(path);

if (path == null) {
return false;
}
if (path == null) {
return false;
}

if (path.contains("/")) {
// we can say that if a user specifies a string which contains the "/" char,
// then it must be a full path (eg. starts with 'Subjects')
for (Tag tag : taggable.getTags()) {
String tagPathName = getPathName(tag);
if (path.contains("/")) {
// we can say that if a user specifies a string which contains the "/" char,
// then it must be a full path (eg. starts with 'Subjects')
for (Tag tag : taggable.getTags()) {
String tagPathName = getPathName(tag);

if (isSearchWithChildren) {
if (isSearchWithChildren) {
if (tagPathName.startsWith(path)) {
return true;
}
}
else if (tagPathName.equals(path)) {
} else if (tagPathName.equals(path)) {
return true;
}
}
} else {
for (Tag tag : taggable.getTags()) {
}
} else {
for (Tag tag : taggable.getTags()) {
String tagPathName = getPathName(tag);

if (isSearchWithChildren){
if (tagPathName.contains(path)) {
return true;
if (isSearchWithChildren) {
if (tagPathName.contains(path)) {
return true;
}
}
if (tagPathName.endsWith(path)) {
return true;
}
}
}
if (tagPathName.endsWith(path)) {
return true;
}
}
}

return false;
}
return false;
}

public Tag getTagBy(Tag rootTag, String[] fullPath) {
public Tag getTagBy(Tag rootTag, String[] fullPath) {

if (rootTag != null) {
for (int i = 1; i < fullPath.length; i++) {
rootTag = getChildWithName(rootTag, fullPath[i]);
if (rootTag == null) {
return null;
}
if (rootTag != null) {
for (int i = 1; i < fullPath.length; i++) {
rootTag = getChildWithName(rootTag, fullPath[i]);
if (rootTag == null) {
return null;
}
}
} else {
return null;
}

return rootTag;

}

public String trimPath(String path) {
path = StringUtils.strip(path, "/ ");
path = StringUtils.trimToNull(path);
return path;
}

private Tag getChildWithName(Tag parent, String childName) {

for (Tag child : parent.getChildTags()) {
if (childName.equals(child.getName())) {
return child;
}
}
return null;
}

private String getPathName(Tag tag) {
String result = tag.getName();
if (tag.getParentTag() != null) {
result = getPathName(tag.getParentTag()) + "/" + result;
}
return result;
}

public void updateSubjectsAsEntities(ObjectContext context) {
var subjectTag = ObjectSelect.query(Tag.class)
.where(Tag.SPECIAL_TYPE.eq(NodeSpecialType.SUBJECTS))
.and(Tag.PARENT_TAG.isNull())
.selectOne(context);

Set<Class<? extends Taggable>> existedRequirements = new HashSet<>();

for (var requirement : subjectTag.getTagRequirements()) {
if (!SUBJECT_ENTITIES.contains(requirement.getEntityClass())) {
context.deleteObject(requirement);
return;
}

existedRequirements.add(requirement.getEntityClass());

if (requirement.getDisplayRule() != null)
requirement.setDisplayRule(null);

if (requirement.getIsRequired())
requirement.setIsRequired(false);

if (requirement.getManyTermsAllowed())
requirement.setManyTermsAllowed(false);
}

SUBJECT_ENTITIES.forEach(entityClass -> {
if(!existedRequirements.contains(entityClass)){
TagRequirement productRequirement = context.newObject(TagRequirement.class);
productRequirement.setEntityIdentifier(TagRequirementFunctions.getTaggableClassForName(entityClass.getSimpleName()));
productRequirement.setTag(subjectTag);
productRequirement.setManyTermsAllowed(false);
productRequirement.setIsRequired(false);
}
} else {
return null;
}

return rootTag;
});

}

public String trimPath(String path) {
path = StringUtils.strip(path, "/ ");
path = StringUtils.trimToNull(path);
return path;
}

private Tag getChildWithName(Tag parent, String childName) {

for (Tag child : parent.getChildTags()) {
if (childName.equals(child.getName())) {
return child;
}
}
return null;
}

private String getPathName(Tag tag) {
String result = tag.getName();
if (tag.getParentTag() != null) {
result = getPathName(tag.getParentTag()) + "/" + result;
}
return result;
}
context.commitChanges();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.google.inject.Singleton;
import ish.math.Country;
import ish.math.CurrencyFormat;
import ish.oncourse.entity.services.TagService;
import ish.oncourse.server.cayenne.Preference;
import ish.oncourse.server.display.DisplayService;
import ish.oncourse.server.integration.PluginsPrefsService;
Expand Down Expand Up @@ -50,6 +51,7 @@ public class PreferenceController extends CommonPreferenceController {
private final ISystemUserService systemUserService;
private final LicenseService licenseService;
private final PluginsPrefsService pluginsPrefsService;
private final TagService tagService;
private ObjectContext objectContext;

@Inject
Expand All @@ -58,19 +60,24 @@ public class PreferenceController extends CommonPreferenceController {
@Inject
public PreferenceController(ICayenneService cayenneService, ISystemUserService systemUserService,
LicenseService licenseService, PluginsPrefsService pluginsPrefsService,
DisplayService displayService) {
DisplayService displayService, TagService tagService) {
this.cayenneService = cayenneService;
this.systemUserService = systemUserService;
this.licenseService = licenseService;
this.pluginsPrefsService = pluginsPrefsService;
this.tagService = tagService;
sharedController = this;

initDisplayPreferencesFromConfigFile(displayService);
}

private void initDisplayPreferencesFromConfigFile(DisplayService displayService) {
if(displayService.getExtendedSearchTypes() != null)
if(displayService.getExtendedSearchTypes() != null) {
setExtendedTypesAllowed(displayService.getExtendedSearchTypes());
if(displayService.getExtendedSearchTypes()){
tagService.updateSubjectsAsEntities(cayenneService.getNewContext());
}
}
}


Expand Down
Loading

0 comments on commit 2e0b858

Please sign in to comment.