001// -------------------------------------------------------------------------------- 002// Copyright 2002-2026 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.control.user.item.server.command; 018 019import com.echothree.control.user.item.common.edit.ItemDescriptionEdit; 020import com.echothree.control.user.item.common.edit.ItemEditFactory; 021import com.echothree.control.user.item.common.form.EditItemDescriptionForm; 022import com.echothree.control.user.item.common.result.EditItemDescriptionResult; 023import com.echothree.control.user.item.common.result.ItemResultFactory; 024import com.echothree.control.user.item.common.spec.ItemDescriptionSpec; 025import com.echothree.model.control.core.common.EntityAttributeTypes; 026import com.echothree.model.control.core.common.MimeTypeUsageTypes; 027import com.echothree.model.control.core.server.control.MimeTypeControl; 028import com.echothree.model.control.item.server.control.ItemControl; 029import com.echothree.model.control.item.server.logic.ItemDescriptionLogic; 030import com.echothree.model.control.item.server.logic.ItemDescriptionLogic.ImageDimensions; 031import com.echothree.model.control.party.common.PartyTypes; 032import com.echothree.model.control.party.server.control.PartyControl; 033import com.echothree.model.control.security.common.SecurityRoleGroups; 034import com.echothree.model.control.security.common.SecurityRoles; 035import com.echothree.model.data.core.server.entity.MimeType; 036import com.echothree.model.data.item.server.entity.Item; 037import com.echothree.model.data.item.server.entity.ItemDescription; 038import com.echothree.model.data.item.server.entity.ItemDescriptionType; 039import com.echothree.model.data.item.server.entity.ItemImageType; 040import com.echothree.model.data.user.common.pk.UserVisitPK; 041import com.echothree.util.common.command.EditMode; 042import com.echothree.util.common.message.ExecutionErrors; 043import com.echothree.util.common.persistence.BasePK; 044import com.echothree.util.common.persistence.type.ByteArray; 045import com.echothree.util.common.validation.FieldDefinition; 046import com.echothree.util.common.validation.FieldType; 047import com.echothree.util.server.control.BaseAbstractEditCommand; 048import com.echothree.util.server.control.CommandSecurityDefinition; 049import com.echothree.util.server.control.PartyTypeDefinition; 050import com.echothree.util.server.control.SecurityRoleDefinition; 051import java.util.List; 052import javax.enterprise.context.Dependent; 053import javax.inject.Inject; 054 055@Dependent 056public class EditItemDescriptionCommand 057 extends BaseAbstractEditCommand<ItemDescriptionSpec, ItemDescriptionEdit, EditItemDescriptionResult, ItemDescription, ItemDescription> { 058 059 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 060 private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS; 061 private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS; 062 063 static { 064 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of( 065 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 066 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of( 067 new SecurityRoleDefinition(SecurityRoleGroups.ItemDescription.name(), SecurityRoles.Edit.name()) 068 )) 069 )); 070 071 SPEC_FIELD_DEFINITIONS = List.of( 072 new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null), 073 new FieldDefinition("ItemDescriptionTypeName", FieldType.ENTITY_NAME, true, null, null), 074 new FieldDefinition("LanguageIsoName", FieldType.ENTITY_NAME, true, null, null) 075 ); 076 077 EDIT_FIELD_DEFINITIONS = List.of( 078 new FieldDefinition("MimeTypeName", FieldType.MIME_TYPE, false, null, null), 079 new FieldDefinition("ItemImageTypeName", FieldType.ENTITY_NAME, false, null, null), 080 new FieldDefinition("ClobDescription", FieldType.STRING, false, 1L, null), 081 new FieldDefinition("StringDescription", FieldType.STRING, false, 1L, 512L) 082 ); 083 } 084 085 @Inject 086 ItemControl itemControl; 087 088 @Inject 089 MimeTypeControl mimeTypeControl; 090 091 @Inject 092 PartyControl partyControl; 093 094 @Inject 095 ItemDescriptionLogic itemDescriptionLogic; 096 097 098 /** Creates a new instance of EditItemDescriptionCommand */ 099 public EditItemDescriptionCommand() { 100 super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS); 101 } 102 103 @Override 104 public EditItemDescriptionResult getResult() { 105 return ItemResultFactory.getEditItemDescriptionResult(); 106 } 107 108 @Override 109 public ItemDescriptionEdit getEdit() { 110 return ItemEditFactory.getItemDescriptionEdit(); 111 } 112 113 ItemDescriptionType itemDescriptionType; 114 Item item; 115 116 @Override 117 public ItemDescription getEntity(EditItemDescriptionResult result) { 118 ItemDescription itemDescription = null; 119 var itemDescriptionTypeName = spec.getItemDescriptionTypeName(); 120 121 itemDescriptionType = itemControl.getItemDescriptionTypeByName(itemDescriptionTypeName); 122 123 if(itemDescriptionType != null) { 124 var itemName = spec.getItemName(); 125 126 item = itemControl.getItemByName(itemName); 127 128 if(item != null) { 129 var languageIsoName = spec.getLanguageIsoName(); 130 var language = partyControl.getLanguageByIsoName(languageIsoName); 131 132 if(language != null) { 133 if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) { 134 itemDescription = itemControl.getItemDescription(itemDescriptionType, item, language); 135 } else { // EditMode.UPDATE 136 itemDescription = itemControl.getItemDescriptionForUpdate(itemDescriptionType, item, language); 137 } 138 139 if(itemDescription == null) { 140 addExecutionError(ExecutionErrors.UnknownItemDescription.name(), itemDescriptionTypeName, itemName, languageIsoName); 141 } 142 } else { 143 addExecutionError(ExecutionErrors.UnknownLanguageIsoName.name(), languageIsoName); 144 } 145 } else { 146 addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName); 147 } 148 } else { 149 addExecutionError(ExecutionErrors.UnknownItemDescriptionTypeName.name(), itemDescriptionTypeName); 150 } 151 152 return itemDescription; 153 } 154 155 @Override 156 public ItemDescription getLockEntity(ItemDescription itemDescription) { 157 return itemDescription; 158 } 159 160 @Override 161 public void fillInResult(EditItemDescriptionResult result, ItemDescription itemDescription) { 162 result.setItemDescription(itemControl.getItemDescriptionTransfer(getUserVisit(), itemDescription)); 163 } 164 165 MimeType mimeType; 166 167 @Override 168 public void doLock(ItemDescriptionEdit edit, ItemDescription itemDescription) { 169 mimeType = itemDescription.getLastDetail().getMimeType(); 170 171 edit.setMimeTypeName(mimeType == null? null: mimeType.getLastDetail().getMimeTypeName()); 172 173 if(mimeType == null) { 174 var itemStringDescription = itemControl.getItemStringDescription(itemDescription); 175 176 if(itemStringDescription != null) { 177 edit.setStringDescription(itemStringDescription.getStringDescription()); 178 } 179 } else { 180 var entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName(); 181 182 // EntityAttributeTypes.BLOB.name() does not return anything in edit 183 if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 184 var itemClobDescription = itemControl.getItemClobDescription(itemDescription); 185 186 if(itemClobDescription != null) { 187 edit.setClobDescription(itemClobDescription.getClobDescription()); 188 } 189 } 190 } 191 } 192 193 ItemImageType itemImageType; 194 ImageDimensions imageDimensions; 195 196 @Override 197 public void canUpdate(ItemDescription itemDescription) { 198 var mimeTypeName = edit.getMimeTypeName(); 199 200 if(mimeTypeName == null) { 201 if(itemDescriptionType.getLastDetail().getMimeTypeUsageType() == null) { 202 var stringDescription = edit.getStringDescription(); 203 204 if(stringDescription == null) { 205 addExecutionError(ExecutionErrors.MissingStringDescription.name()); 206 } 207 } else { 208 // No mimeTypeName was supplied, but yet we required a MimeTypeUsageType 209 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 210 } 211 } else { 212 mimeType = mimeTypeControl.getMimeTypeByName(mimeTypeName); 213 214 if(mimeType != null) { 215 var mimeTypeUsageType = itemDescriptionType.getLastDetail().getMimeTypeUsageType(); 216 217 if(mimeTypeUsageType != null) { 218 var mimeTypeUsage = mimeTypeControl.getMimeTypeUsage(mimeType, mimeTypeUsageType); 219 220 if(mimeTypeUsage != null) { 221 var mimeTypeDetail = mimeType.getLastDetail(); 222 var entityAttributeType = mimeTypeDetail.getEntityAttributeType(); 223 var entityAttributeTypeName = entityAttributeType.getEntityAttributeTypeName(); 224 225 if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) { 226 var blobDescription = edit.getBlobDescription(); 227 228 if(blobDescription == null) { 229 addExecutionError(ExecutionErrors.MissingBlobDescription.name()); 230 } else { 231 var mimeTypeUsageTypeName = mimeTypeUsageType.getMimeTypeUsageTypeName(); 232 233 if(mimeTypeUsageTypeName.equals(MimeTypeUsageTypes.IMAGE.name())) { 234 var itemImageTypeName = edit.getItemImageTypeName(); 235 236 if(itemImageTypeName != null) { 237 itemImageType = itemControl.getItemImageTypeByName(itemImageTypeName); 238 239 if(itemImageType != null) { 240 imageDimensions = itemDescriptionLogic.getImageDimensions(mimeTypeDetail.getMimeTypeName(), blobDescription); 241 242 if(imageDimensions == null) { 243 addExecutionError(ExecutionErrors.InvalidImage.name()); 244 } else { 245 var itemImageDescriptionType = itemControl.getItemImageDescriptionType(itemDescriptionType); 246 247 if(itemImageDescriptionType != null) { 248 var minimumHeight = itemImageDescriptionType.getMinimumHeight(); 249 var minimumWidth = itemImageDescriptionType.getMinimumWidth(); 250 var maximumHeight = itemImageDescriptionType.getMaximumHeight(); 251 var maximumWidth = itemImageDescriptionType.getMaximumWidth(); 252 var imageHeight = imageDimensions.getHeight(); 253 var imageWidth = imageDimensions.getWidth(); 254 255 if(minimumHeight != null && imageHeight < minimumHeight) { 256 addExecutionError(ExecutionErrors.ImageHeightLessThanMinimum.name(), imageHeight.toString(), minimumHeight.toString()); 257 } 258 259 if(minimumWidth != null && imageWidth < minimumWidth) { 260 addExecutionError(ExecutionErrors.ImageWidthLessThanMinimum.name(), imageWidth.toString(), minimumWidth.toString()); 261 } 262 263 if(maximumHeight != null && imageHeight > maximumHeight) { 264 addExecutionError(ExecutionErrors.ImageHeightGreaterThanMaximum.name(), imageHeight.toString(), maximumHeight.toString()); 265 } 266 267 if(maximumWidth != null && imageWidth > maximumWidth) { 268 addExecutionError(ExecutionErrors.ImageWidthGreaterThanMaximum.name(), imageWidth.toString(), maximumWidth.toString()); 269 } 270 } 271 } 272 } else { 273 addExecutionError(ExecutionErrors.UnknownItemImageTypeName.name(), itemImageTypeName); 274 } 275 } else { 276 addExecutionError(ExecutionErrors.MissingRequiredItemImageTypeName.name()); 277 } 278 } 279 } 280 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 281 var clobDescription = edit.getClobDescription(); 282 283 if(clobDescription == null) { 284 addExecutionError(ExecutionErrors.MissingClobDescription.name()); 285 } 286 } else { 287 addExecutionError(ExecutionErrors.UnknownEntityAttributeTypeName.name(), 288 entityAttributeTypeName); 289 } 290 } else { 291 addExecutionError(ExecutionErrors.UnknownMimeTypeUsage.name()); 292 } 293 } else { 294 // mimeTypeName was supplied, and there shouldn't be one 295 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 296 } 297 } else { 298 addExecutionError(ExecutionErrors.UnknownMimeTypeName.name(), mimeTypeName); 299 } 300 } 301 } 302 303 @Override 304 public void doUpdate(ItemDescription itemDescription) { 305 var partyPK = getPartyPK(); 306 307 if(mimeType == null) { 308 var stringDescription = edit.getStringDescription(); 309 310 updateItemDescription(itemControl, item, null, partyPK, itemDescription, null, null, stringDescription); 311 } else { 312 var entityAttributeType = mimeType.getLastDetail().getEntityAttributeType(); 313 var entityAttributeTypeName = entityAttributeType.getEntityAttributeTypeName(); 314 315 if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) { 316 var blobDescription = edit.getBlobDescription(); 317 318 updateItemDescription(itemControl, item, mimeType, partyPK, itemDescription, blobDescription, null, null); 319 } else { 320 if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 321 var clobDescription = edit.getClobDescription(); 322 323 updateItemDescription(itemControl, item, mimeType, partyPK, itemDescription, null, clobDescription, null); 324 } 325 } 326 } 327 } 328 329 protected void updateItemDescription(ItemControl itemControl, Item item, MimeType mimeType, BasePK updatedBy, 330 ItemDescription itemDescription, ByteArray blobDescription, String clobDescription, String stringDescription) { 331 var itemDescriptionDetailValue = itemControl.getItemDescriptionDetailValueForUpdate(itemDescription); 332 333 itemDescriptionDetailValue.setMimeTypePK(mimeType == null? null: mimeType.getPrimaryKey()); 334 itemControl.updateItemDescriptionFromValue(itemDescriptionDetailValue, updatedBy); 335 336 var itemBlobDescription = itemControl.getItemBlobDescriptionForUpdate(itemDescription); 337 338 if(itemBlobDescription != null) { 339 if(blobDescription == null) { 340 itemControl.deleteItemBlobDescription(itemBlobDescription, updatedBy); 341 itemControl.deleteItemImageDescriptionByItemDescription(itemDescription, updatedBy); 342 } else { 343 var itemBlobDescriptionValue = itemControl.getItemBlobDescriptionValue(itemBlobDescription); 344 var itemImageDescriptionValue = itemControl.getItemImageDescriptionValueForUpdate(itemDescription); 345 346 itemBlobDescriptionValue.setBlobDescription(blobDescription); 347 itemControl.updateItemBlobDescriptionFromValue(itemBlobDescriptionValue, updatedBy); 348 349 if(imageDimensions != null) { 350 itemImageDescriptionValue.setHeight(imageDimensions.getHeight()); 351 itemImageDescriptionValue.setWidth(imageDimensions.getWidth()); 352 itemImageDescriptionValue.setScaledFromParent(false); 353 354 itemControl.updateItemImageDescriptionFromValue(itemImageDescriptionValue, updatedBy); 355 } 356 357 if(itemBlobDescriptionValue.hasBeenModified()) { 358 itemDescriptionLogic.deleteItemImageDescriptionChildren(itemDescription, updatedBy); 359 } 360 } 361 } else if(blobDescription != null) { 362 itemControl.createItemBlobDescription(itemDescription, blobDescription, updatedBy); 363 364 if(imageDimensions != null) { 365 itemControl.createItemImageDescription(itemDescription, itemImageType, imageDimensions.getHeight(), imageDimensions.getWidth(), false, 366 updatedBy); 367 } 368 369 itemDescriptionLogic.deleteItemImageDescriptionChildren(itemDescription, updatedBy); 370 } 371 372 var itemClobDescription = itemControl.getItemClobDescriptionForUpdate(itemDescription); 373 374 if(itemClobDescription != null) { 375 if(clobDescription == null) { 376 itemControl.deleteItemClobDescription(itemClobDescription, updatedBy); 377 } else { 378 var itemClobDescriptionValue = itemControl.getItemClobDescriptionValue(itemClobDescription); 379 380 itemClobDescriptionValue.setClobDescription(clobDescription); 381 itemControl.updateItemClobDescriptionFromValue(itemClobDescriptionValue, updatedBy); 382 } 383 } else if(clobDescription != null) { 384 itemControl.createItemClobDescription(itemDescription, clobDescription, updatedBy); 385 } 386 387 var itemStringDescription = itemControl.getItemStringDescriptionForUpdate(itemDescription); 388 389 if(itemStringDescription != null) { 390 if(stringDescription == null) { 391 itemControl.deleteItemStringDescription(itemStringDescription, updatedBy); 392 } else { 393 var itemStringDescriptionValue = itemControl.getItemStringDescriptionValue(itemStringDescription); 394 395 itemStringDescriptionValue.setStringDescription(stringDescription); 396 itemControl.updateItemStringDescriptionFromValue(itemStringDescriptionValue, updatedBy); 397 } 398 } else if(stringDescription != null) { 399 itemControl.createItemStringDescription(itemDescription, stringDescription, updatedBy); 400 } 401 } 402 403}