001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 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 com.echothree.util.server.persistence.Session; 052import java.util.Arrays; 053import java.util.Collections; 054import java.util.List; 055import javax.enterprise.context.RequestScoped; 056 057@RequestScoped 058public class EditItemDescriptionCommand 059 extends BaseAbstractEditCommand<ItemDescriptionSpec, ItemDescriptionEdit, EditItemDescriptionResult, ItemDescription, ItemDescription> { 060 061 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 062 private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS; 063 private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS; 064 065 static { 066 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(Collections.unmodifiableList(Arrays.asList( 067 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 068 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), Collections.unmodifiableList(Arrays.asList( 069 new SecurityRoleDefinition(SecurityRoleGroups.ItemDescription.name(), SecurityRoles.Edit.name()) 070 ))) 071 ))); 072 073 SPEC_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList( 074 new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null), 075 new FieldDefinition("ItemDescriptionTypeName", FieldType.ENTITY_NAME, true, null, null), 076 new FieldDefinition("LanguageIsoName", FieldType.ENTITY_NAME, true, null, null) 077 )); 078 079 EDIT_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList( 080 new FieldDefinition("MimeTypeName", FieldType.MIME_TYPE, false, null, null), 081 new FieldDefinition("ItemImageTypeName", FieldType.ENTITY_NAME, false, null, null), 082 new FieldDefinition("ClobDescription", FieldType.STRING, false, 1L, null), 083 new FieldDefinition("StringDescription", FieldType.STRING, false, 1L, 512L) 084 )); 085 } 086 087 /** Creates a new instance of EditItemDescriptionCommand */ 088 public EditItemDescriptionCommand() { 089 super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS); 090 } 091 092 @Override 093 public EditItemDescriptionResult getResult() { 094 return ItemResultFactory.getEditItemDescriptionResult(); 095 } 096 097 @Override 098 public ItemDescriptionEdit getEdit() { 099 return ItemEditFactory.getItemDescriptionEdit(); 100 } 101 102 ItemDescriptionType itemDescriptionType; 103 Item item; 104 105 @Override 106 public ItemDescription getEntity(EditItemDescriptionResult result) { 107 var itemControl = Session.getModelController(ItemControl.class); 108 ItemDescription itemDescription = null; 109 var itemDescriptionTypeName = spec.getItemDescriptionTypeName(); 110 111 itemDescriptionType = itemControl.getItemDescriptionTypeByName(itemDescriptionTypeName); 112 113 if(itemDescriptionType != null) { 114 var itemName = spec.getItemName(); 115 116 item = itemControl.getItemByName(itemName); 117 118 if(item != null) { 119 var partyControl = Session.getModelController(PartyControl.class); 120 var languageIsoName = spec.getLanguageIsoName(); 121 var language = partyControl.getLanguageByIsoName(languageIsoName); 122 123 if(language != null) { 124 if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) { 125 itemDescription = itemControl.getItemDescription(itemDescriptionType, item, language); 126 } else { // EditMode.UPDATE 127 itemDescription = itemControl.getItemDescriptionForUpdate(itemDescriptionType, item, language); 128 } 129 130 if(itemDescription == null) { 131 addExecutionError(ExecutionErrors.UnknownItemDescription.name(), itemDescriptionTypeName, itemName, languageIsoName); 132 } 133 } else { 134 addExecutionError(ExecutionErrors.UnknownLanguageIsoName.name(), languageIsoName); 135 } 136 } else { 137 addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName); 138 } 139 } else { 140 addExecutionError(ExecutionErrors.UnknownItemDescriptionTypeName.name(), itemDescriptionTypeName); 141 } 142 143 return itemDescription; 144 } 145 146 @Override 147 public ItemDescription getLockEntity(ItemDescription itemDescription) { 148 return itemDescription; 149 } 150 151 @Override 152 public void fillInResult(EditItemDescriptionResult result, ItemDescription itemDescription) { 153 var itemControl = Session.getModelController(ItemControl.class); 154 155 result.setItemDescription(itemControl.getItemDescriptionTransfer(getUserVisit(), itemDescription)); 156 } 157 158 MimeType mimeType; 159 160 @Override 161 public void doLock(ItemDescriptionEdit edit, ItemDescription itemDescription) { 162 var itemControl = Session.getModelController(ItemControl.class); 163 164 mimeType = itemDescription.getLastDetail().getMimeType(); 165 166 edit.setMimeTypeName(mimeType == null? null: mimeType.getLastDetail().getMimeTypeName()); 167 168 if(mimeType == null) { 169 var itemStringDescription = itemControl.getItemStringDescription(itemDescription); 170 171 if(itemStringDescription != null) { 172 edit.setStringDescription(itemStringDescription.getStringDescription()); 173 } 174 } else { 175 var entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName(); 176 177 // EntityAttributeTypes.BLOB.name() does not return anything in edit 178 if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 179 var itemClobDescription = itemControl.getItemClobDescription(itemDescription); 180 181 if(itemClobDescription != null) { 182 edit.setClobDescription(itemClobDescription.getClobDescription()); 183 } 184 } 185 } 186 } 187 188 ItemImageType itemImageType; 189 ImageDimensions imageDimensions; 190 191 @Override 192 public void canUpdate(ItemDescription itemDescription) { 193 var mimeTypeName = edit.getMimeTypeName(); 194 195 if(mimeTypeName == null) { 196 if(itemDescriptionType.getLastDetail().getMimeTypeUsageType() == null) { 197 var stringDescription = edit.getStringDescription(); 198 199 if(stringDescription == null) { 200 addExecutionError(ExecutionErrors.MissingStringDescription.name()); 201 } 202 } else { 203 // No mimeTypeName was supplied, but yet we required a MimeTypeUsageType 204 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 205 } 206 } else { 207 var mimeTypeControl = Session.getModelController(MimeTypeControl.class); 208 209 mimeType = mimeTypeControl.getMimeTypeByName(mimeTypeName); 210 211 if(mimeType != null) { 212 var mimeTypeUsageType = itemDescriptionType.getLastDetail().getMimeTypeUsageType(); 213 214 if(mimeTypeUsageType != null) { 215 var mimeTypeUsage = mimeTypeControl.getMimeTypeUsage(mimeType, mimeTypeUsageType); 216 217 if(mimeTypeUsage != null) { 218 var mimeTypeDetail = mimeType.getLastDetail(); 219 var entityAttributeType = mimeTypeDetail.getEntityAttributeType(); 220 var entityAttributeTypeName = entityAttributeType.getEntityAttributeTypeName(); 221 222 if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) { 223 var blobDescription = edit.getBlobDescription(); 224 225 if(blobDescription == null) { 226 addExecutionError(ExecutionErrors.MissingBlobDescription.name()); 227 } else { 228 var mimeTypeUsageTypeName = mimeTypeUsageType.getMimeTypeUsageTypeName(); 229 230 if(mimeTypeUsageTypeName.equals(MimeTypeUsageTypes.IMAGE.name())) { 231 var itemImageTypeName = edit.getItemImageTypeName(); 232 233 if(itemImageTypeName != null) { 234 var itemControl = Session.getModelController(ItemControl.class); 235 236 itemImageType = itemControl.getItemImageTypeByName(itemImageTypeName); 237 238 if(itemImageType != null) { 239 imageDimensions = ItemDescriptionLogic.getInstance().getImageDimensions(mimeTypeDetail.getMimeTypeName(), blobDescription); 240 241 if(imageDimensions == null) { 242 addExecutionError(ExecutionErrors.InvalidImage.name()); 243 } else { 244 var itemImageDescriptionType = itemControl.getItemImageDescriptionType(itemDescriptionType); 245 246 if(itemImageDescriptionType != null) { 247 var minimumHeight = itemImageDescriptionType.getMinimumHeight(); 248 var minimumWidth = itemImageDescriptionType.getMinimumWidth(); 249 var maximumHeight = itemImageDescriptionType.getMaximumHeight(); 250 var maximumWidth = itemImageDescriptionType.getMaximumWidth(); 251 var imageHeight = imageDimensions.getHeight(); 252 var imageWidth = imageDimensions.getWidth(); 253 254 if(minimumHeight != null && imageHeight < minimumHeight) { 255 addExecutionError(ExecutionErrors.ImageHeightLessThanMinimum.name(), imageHeight.toString(), minimumHeight.toString()); 256 } 257 258 if(minimumWidth != null && imageWidth < minimumWidth) { 259 addExecutionError(ExecutionErrors.ImageWidthLessThanMinimum.name(), imageWidth.toString(), minimumWidth.toString()); 260 } 261 262 if(maximumHeight != null && imageHeight > maximumHeight) { 263 addExecutionError(ExecutionErrors.ImageHeightGreaterThanMaximum.name(), imageHeight.toString(), maximumHeight.toString()); 264 } 265 266 if(maximumWidth != null && imageWidth > maximumWidth) { 267 addExecutionError(ExecutionErrors.ImageWidthGreaterThanMaximum.name(), imageWidth.toString(), maximumWidth.toString()); 268 } 269 } 270 } 271 } else { 272 addExecutionError(ExecutionErrors.UnknownItemImageTypeName.name(), itemImageTypeName); 273 } 274 } else { 275 addExecutionError(ExecutionErrors.MissingRequiredItemImageTypeName.name()); 276 } 277 } 278 } 279 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 280 var clobDescription = edit.getClobDescription(); 281 282 if(clobDescription == null) { 283 addExecutionError(ExecutionErrors.MissingClobDescription.name()); 284 } 285 } else { 286 addExecutionError(ExecutionErrors.UnknownEntityAttributeTypeName.name(), 287 entityAttributeTypeName); 288 } 289 } else { 290 addExecutionError(ExecutionErrors.UnknownMimeTypeUsage.name()); 291 } 292 } else { 293 // mimeTypeName was supplied, and there shouldn't be one 294 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 295 } 296 } else { 297 addExecutionError(ExecutionErrors.UnknownMimeTypeName.name(), mimeTypeName); 298 } 299 } 300 } 301 302 @Override 303 public void doUpdate(ItemDescription itemDescription) { 304 var itemControl = Session.getModelController(ItemControl.class); 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.getInstance().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.getInstance().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}