001// -------------------------------------------------------------------------------- 002// Copyright 2002-2024 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.item.server.control.ItemControl; 028import com.echothree.model.control.item.server.logic.ItemDescriptionLogic; 029import com.echothree.model.control.item.server.logic.ItemDescriptionLogic.ImageDimensions; 030import com.echothree.model.control.party.common.PartyTypes; 031import com.echothree.model.control.party.server.control.PartyControl; 032import com.echothree.model.control.security.common.SecurityRoleGroups; 033import com.echothree.model.control.security.common.SecurityRoles; 034import com.echothree.model.data.core.server.entity.EntityAttributeType; 035import com.echothree.model.data.core.server.entity.MimeType; 036import com.echothree.model.data.core.server.entity.MimeTypeDetail; 037import com.echothree.model.data.core.server.entity.MimeTypeUsage; 038import com.echothree.model.data.core.server.entity.MimeTypeUsageType; 039import com.echothree.model.data.item.server.entity.Item; 040import com.echothree.model.data.item.server.entity.ItemBlobDescription; 041import com.echothree.model.data.item.server.entity.ItemClobDescription; 042import com.echothree.model.data.item.server.entity.ItemDescription; 043import com.echothree.model.data.item.server.entity.ItemDescriptionType; 044import com.echothree.model.data.item.server.entity.ItemImageDescriptionType; 045import com.echothree.model.data.item.server.entity.ItemImageType; 046import com.echothree.model.data.item.server.entity.ItemStringDescription; 047import com.echothree.model.data.item.server.value.ItemBlobDescriptionValue; 048import com.echothree.model.data.item.server.value.ItemClobDescriptionValue; 049import com.echothree.model.data.item.server.value.ItemDescriptionDetailValue; 050import com.echothree.model.data.item.server.value.ItemImageDescriptionValue; 051import com.echothree.model.data.item.server.value.ItemStringDescriptionValue; 052import com.echothree.model.data.party.server.entity.Language; 053import com.echothree.model.data.user.common.pk.UserVisitPK; 054import com.echothree.util.common.message.ExecutionErrors; 055import com.echothree.util.common.validation.FieldDefinition; 056import com.echothree.util.common.validation.FieldType; 057import com.echothree.util.common.command.EditMode; 058import com.echothree.util.common.persistence.BasePK; 059import com.echothree.util.common.persistence.type.ByteArray; 060import com.echothree.util.server.control.BaseAbstractEditCommand; 061import com.echothree.util.server.control.CommandSecurityDefinition; 062import com.echothree.util.server.control.PartyTypeDefinition; 063import com.echothree.util.server.control.SecurityRoleDefinition; 064import com.echothree.util.server.persistence.Session; 065import java.util.Arrays; 066import java.util.Collections; 067import java.util.List; 068 069public class EditItemDescriptionCommand 070 extends BaseAbstractEditCommand<ItemDescriptionSpec, ItemDescriptionEdit, EditItemDescriptionResult, ItemDescription, ItemDescription> { 071 072 private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION; 073 private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS; 074 private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS; 075 076 static { 077 COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(Collections.unmodifiableList(Arrays.asList( 078 new PartyTypeDefinition(PartyTypes.UTILITY.name(), null), 079 new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), Collections.unmodifiableList(Arrays.asList( 080 new SecurityRoleDefinition(SecurityRoleGroups.ItemDescription.name(), SecurityRoles.Edit.name()) 081 ))) 082 ))); 083 084 SPEC_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList( 085 new FieldDefinition("ItemName", FieldType.ENTITY_NAME, true, null, null), 086 new FieldDefinition("ItemDescriptionTypeName", FieldType.ENTITY_NAME, true, null, null), 087 new FieldDefinition("LanguageIsoName", FieldType.ENTITY_NAME, true, null, null) 088 )); 089 090 EDIT_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList( 091 new FieldDefinition("MimeTypeName", FieldType.MIME_TYPE, false, null, null), 092 new FieldDefinition("ItemImageTypeName", FieldType.ENTITY_NAME, false, null, null), 093 new FieldDefinition("ClobDescription", FieldType.STRING, false, 1L, null), 094 new FieldDefinition("StringDescription", FieldType.STRING, false, 1L, 512L) 095 )); 096 } 097 098 /** Creates a new instance of EditItemDescriptionCommand */ 099 public EditItemDescriptionCommand(UserVisitPK userVisitPK, EditItemDescriptionForm form) { 100 super(userVisitPK, form, 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 var itemControl = Session.getModelController(ItemControl.class); 119 ItemDescription itemDescription = null; 120 String itemDescriptionTypeName = spec.getItemDescriptionTypeName(); 121 122 itemDescriptionType = itemControl.getItemDescriptionTypeByName(itemDescriptionTypeName); 123 124 if(itemDescriptionType != null) { 125 String itemName = spec.getItemName(); 126 127 item = itemControl.getItemByName(itemName); 128 129 if(item != null) { 130 var partyControl = Session.getModelController(PartyControl.class); 131 String languageIsoName = spec.getLanguageIsoName(); 132 Language language = partyControl.getLanguageByIsoName(languageIsoName); 133 134 if(language != null) { 135 if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) { 136 itemDescription = itemControl.getItemDescription(itemDescriptionType, item, language); 137 } else { // EditMode.UPDATE 138 itemDescription = itemControl.getItemDescriptionForUpdate(itemDescriptionType, item, language); 139 } 140 141 if(itemDescription == null) { 142 addExecutionError(ExecutionErrors.UnknownItemDescription.name(), itemDescriptionTypeName, itemName, languageIsoName); 143 } 144 } else { 145 addExecutionError(ExecutionErrors.UnknownLanguageIsoName.name(), languageIsoName); 146 } 147 } else { 148 addExecutionError(ExecutionErrors.UnknownItemName.name(), itemName); 149 } 150 } else { 151 addExecutionError(ExecutionErrors.UnknownItemDescriptionTypeName.name(), itemDescriptionTypeName); 152 } 153 154 return itemDescription; 155 } 156 157 @Override 158 public ItemDescription getLockEntity(ItemDescription itemDescription) { 159 return itemDescription; 160 } 161 162 @Override 163 public void fillInResult(EditItemDescriptionResult result, ItemDescription itemDescription) { 164 var itemControl = Session.getModelController(ItemControl.class); 165 166 result.setItemDescription(itemControl.getItemDescriptionTransfer(getUserVisit(), itemDescription)); 167 } 168 169 MimeType mimeType; 170 171 @Override 172 public void doLock(ItemDescriptionEdit edit, ItemDescription itemDescription) { 173 var itemControl = Session.getModelController(ItemControl.class); 174 175 mimeType = itemDescription.getLastDetail().getMimeType(); 176 177 edit.setMimeTypeName(mimeType == null? null: mimeType.getLastDetail().getMimeTypeName()); 178 179 if(mimeType == null) { 180 ItemStringDescription itemStringDescription = itemControl.getItemStringDescription(itemDescription); 181 182 if(itemStringDescription != null) { 183 edit.setStringDescription(itemStringDescription.getStringDescription()); 184 } 185 } else { 186 String entityAttributeTypeName = mimeType.getLastDetail().getEntityAttributeType().getEntityAttributeTypeName(); 187 188 // EntityAttributeTypes.BLOB.name() does not return anything in edit 189 if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 190 ItemClobDescription itemClobDescription = itemControl.getItemClobDescription(itemDescription); 191 192 if(itemClobDescription != null) { 193 edit.setClobDescription(itemClobDescription.getClobDescription()); 194 } 195 } 196 } 197 } 198 199 ItemImageType itemImageType; 200 ImageDimensions imageDimensions; 201 202 @Override 203 public void canUpdate(ItemDescription itemDescription) { 204 String mimeTypeName = edit.getMimeTypeName(); 205 206 if(mimeTypeName == null) { 207 if(itemDescriptionType.getLastDetail().getMimeTypeUsageType() == null) { 208 String stringDescription = edit.getStringDescription(); 209 210 if(stringDescription == null) { 211 addExecutionError(ExecutionErrors.MissingStringDescription.name()); 212 } 213 } else { 214 // No mimeTypeName was supplied, but yet we required a MimeTypeUsageType 215 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 216 } 217 } else { 218 var coreControl = getCoreControl(); 219 220 mimeType = coreControl.getMimeTypeByName(mimeTypeName); 221 222 if(mimeType != null) { 223 MimeTypeUsageType mimeTypeUsageType = itemDescriptionType.getLastDetail().getMimeTypeUsageType(); 224 225 if(mimeTypeUsageType != null) { 226 MimeTypeUsage mimeTypeUsage = coreControl.getMimeTypeUsage(mimeType, mimeTypeUsageType); 227 228 if(mimeTypeUsage != null) { 229 MimeTypeDetail mimeTypeDetail = mimeType.getLastDetail(); 230 EntityAttributeType entityAttributeType = mimeTypeDetail.getEntityAttributeType(); 231 String entityAttributeTypeName = entityAttributeType.getEntityAttributeTypeName(); 232 233 if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) { 234 ByteArray blobDescription = edit.getBlobDescription(); 235 236 if(blobDescription == null) { 237 addExecutionError(ExecutionErrors.MissingBlobDescription.name()); 238 } else { 239 String mimeTypeUsageTypeName = mimeTypeUsageType.getMimeTypeUsageTypeName(); 240 241 if(mimeTypeUsageTypeName.equals(MimeTypeUsageTypes.IMAGE.name())) { 242 String itemImageTypeName = edit.getItemImageTypeName(); 243 244 if(itemImageTypeName != null) { 245 var itemControl = Session.getModelController(ItemControl.class); 246 247 itemImageType = itemControl.getItemImageTypeByName(itemImageTypeName); 248 249 if(itemImageType != null) { 250 imageDimensions = ItemDescriptionLogic.getInstance().getImageDimensions(mimeTypeDetail.getMimeTypeName(), blobDescription); 251 252 if(imageDimensions == null) { 253 addExecutionError(ExecutionErrors.InvalidImage.name()); 254 } else { 255 ItemImageDescriptionType itemImageDescriptionType = itemControl.getItemImageDescriptionType(itemDescriptionType); 256 257 if(itemImageDescriptionType != null) { 258 Integer minimumHeight = itemImageDescriptionType.getMinimumHeight(); 259 Integer minimumWidth = itemImageDescriptionType.getMinimumWidth(); 260 Integer maximumHeight = itemImageDescriptionType.getMaximumHeight(); 261 Integer maximumWidth = itemImageDescriptionType.getMaximumWidth(); 262 Integer imageHeight = imageDimensions.getHeight(); 263 Integer imageWidth = imageDimensions.getWidth(); 264 265 if(minimumHeight != null && imageHeight < minimumHeight) { 266 addExecutionError(ExecutionErrors.ImageHeightLessThanMinimum.name(), imageHeight.toString(), minimumHeight.toString()); 267 } 268 269 if(minimumWidth != null && imageWidth < minimumWidth) { 270 addExecutionError(ExecutionErrors.ImageWidthLessThanMinimum.name(), imageWidth.toString(), minimumWidth.toString()); 271 } 272 273 if(maximumHeight != null && imageHeight > maximumHeight) { 274 addExecutionError(ExecutionErrors.ImageHeightGreaterThanMaximum.name(), imageHeight.toString(), maximumHeight.toString()); 275 } 276 277 if(maximumWidth != null && imageWidth > maximumWidth) { 278 addExecutionError(ExecutionErrors.ImageWidthGreaterThanMaximum.name(), imageWidth.toString(), maximumWidth.toString()); 279 } 280 } 281 } 282 } else { 283 addExecutionError(ExecutionErrors.UnknownItemImageTypeName.name(), itemImageTypeName); 284 } 285 } else { 286 addExecutionError(ExecutionErrors.MissingRequiredItemImageTypeName.name()); 287 } 288 } 289 } 290 } else if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 291 String clobDescription = edit.getClobDescription(); 292 293 if(clobDescription == null) { 294 addExecutionError(ExecutionErrors.MissingClobDescription.name()); 295 } 296 } else { 297 addExecutionError(ExecutionErrors.UnknownEntityAttributeTypeName.name(), 298 entityAttributeTypeName); 299 } 300 } else { 301 addExecutionError(ExecutionErrors.UnknownMimeTypeUsage.name()); 302 } 303 } else { 304 // mimeTypeName was supplied, and there shouldn't be one 305 addExecutionError(ExecutionErrors.InvalidMimeType.name()); 306 } 307 } else { 308 addExecutionError(ExecutionErrors.UnknownMimeTypeName.name(), mimeTypeName); 309 } 310 } 311 } 312 313 @Override 314 public void doUpdate(ItemDescription itemDescription) { 315 var itemControl = Session.getModelController(ItemControl.class); 316 var partyPK = getPartyPK(); 317 318 if(mimeType == null) { 319 String stringDescription = edit.getStringDescription(); 320 321 updateItemDescription(itemControl, item, null, partyPK, itemDescription, null, null, stringDescription); 322 } else { 323 EntityAttributeType entityAttributeType = mimeType.getLastDetail().getEntityAttributeType(); 324 String entityAttributeTypeName = entityAttributeType.getEntityAttributeTypeName(); 325 326 if(entityAttributeTypeName.equals(EntityAttributeTypes.BLOB.name())) { 327 ByteArray blobDescription = edit.getBlobDescription(); 328 329 updateItemDescription(itemControl, item, mimeType, partyPK, itemDescription, blobDescription, null, null); 330 } else { 331 if(entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())) { 332 String clobDescription = edit.getClobDescription(); 333 334 updateItemDescription(itemControl, item, mimeType, partyPK, itemDescription, null, clobDescription, null); 335 } 336 } 337 } 338 } 339 340 protected void updateItemDescription(ItemControl itemControl, Item item, MimeType mimeType, BasePK updatedBy, 341 ItemDescription itemDescription, ByteArray blobDescription, String clobDescription, String stringDescription) { 342 ItemDescriptionDetailValue itemDescriptionDetailValue = itemControl.getItemDescriptionDetailValueForUpdate(itemDescription); 343 344 itemDescriptionDetailValue.setMimeTypePK(mimeType == null? null: mimeType.getPrimaryKey()); 345 itemControl.updateItemDescriptionFromValue(itemDescriptionDetailValue, updatedBy); 346 347 ItemBlobDescription itemBlobDescription = itemControl.getItemBlobDescriptionForUpdate(itemDescription); 348 349 if(itemBlobDescription != null) { 350 if(blobDescription == null) { 351 itemControl.deleteItemBlobDescription(itemBlobDescription, updatedBy); 352 itemControl.deleteItemImageDescriptionByItemDescription(itemDescription, updatedBy); 353 } else { 354 ItemBlobDescriptionValue itemBlobDescriptionValue = itemControl.getItemBlobDescriptionValue(itemBlobDescription); 355 ItemImageDescriptionValue itemImageDescriptionValue = itemControl.getItemImageDescriptionValueForUpdate(itemDescription); 356 357 itemBlobDescriptionValue.setBlobDescription(blobDescription); 358 itemControl.updateItemBlobDescriptionFromValue(itemBlobDescriptionValue, updatedBy); 359 360 if(imageDimensions != null) { 361 itemImageDescriptionValue.setHeight(imageDimensions.getHeight()); 362 itemImageDescriptionValue.setWidth(imageDimensions.getWidth()); 363 itemImageDescriptionValue.setScaledFromParent(Boolean.FALSE); 364 365 itemControl.updateItemImageDescriptionFromValue(itemImageDescriptionValue, updatedBy); 366 } 367 368 if(itemBlobDescriptionValue.hasBeenModified()) { 369 ItemDescriptionLogic.getInstance().deleteItemImageDescriptionChildren(itemDescription, updatedBy); 370 } 371 } 372 } else if(blobDescription != null) { 373 itemControl.createItemBlobDescription(itemDescription, blobDescription, updatedBy); 374 375 if(imageDimensions != null) { 376 itemControl.createItemImageDescription(itemDescription, itemImageType, imageDimensions.getHeight(), imageDimensions.getWidth(), Boolean.FALSE, 377 updatedBy); 378 } 379 380 ItemDescriptionLogic.getInstance().deleteItemImageDescriptionChildren(itemDescription, updatedBy); 381 } 382 383 ItemClobDescription itemClobDescription = itemControl.getItemClobDescriptionForUpdate(itemDescription); 384 385 if(itemClobDescription != null) { 386 if(clobDescription == null) { 387 itemControl.deleteItemClobDescription(itemClobDescription, updatedBy); 388 } else { 389 ItemClobDescriptionValue itemClobDescriptionValue = itemControl.getItemClobDescriptionValue(itemClobDescription); 390 391 itemClobDescriptionValue.setClobDescription(clobDescription); 392 itemControl.updateItemClobDescriptionFromValue(itemClobDescriptionValue, updatedBy); 393 } 394 } else if(clobDescription != null) { 395 itemControl.createItemClobDescription(itemDescription, clobDescription, updatedBy); 396 } 397 398 ItemStringDescription itemStringDescription = itemControl.getItemStringDescriptionForUpdate(itemDescription); 399 400 if(itemStringDescription != null) { 401 if(stringDescription == null) { 402 itemControl.deleteItemStringDescription(itemStringDescription, updatedBy); 403 } else { 404 ItemStringDescriptionValue itemStringDescriptionValue = itemControl.getItemStringDescriptionValue(itemStringDescription); 405 406 itemStringDescriptionValue.setStringDescription(stringDescription); 407 itemControl.updateItemStringDescriptionFromValue(itemStringDescriptionValue, updatedBy); 408 } 409 } else if(stringDescription != null) { 410 itemControl.createItemStringDescription(itemDescription, stringDescription, updatedBy); 411 } 412 } 413 414}