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}