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.util.server.control;
018
019import com.echothree.model.control.core.common.EntityAttributeTypes;
020import com.echothree.model.control.core.common.MimeTypes;
021import com.echothree.model.control.core.server.control.MimeTypeControl;
022import com.echothree.model.data.user.common.pk.UserVisitPK;
023import com.echothree.util.common.command.BaseResult;
024import com.echothree.util.common.command.CommandResult;
025import com.echothree.util.common.form.BaseForm;
026import com.echothree.util.common.form.ValidationResult;
027import com.echothree.util.common.message.ExecutionErrors;
028import com.echothree.util.common.validation.FieldDefinition;
029import com.echothree.util.server.validation.Validator;
030import java.util.List;
031import java.util.concurrent.Future;
032import javax.inject.Inject;
033
034public abstract class BaseSimpleCommand<F extends BaseForm>
035        extends BaseCommand {
036
037    protected F form;
038    private List<FieldDefinition> formFieldDefinitions;
039    boolean allowLimits;
040
041    @Inject
042    protected MimeTypeControl mimeTypeControl;
043
044    private void init(F form, List<FieldDefinition> formFieldDefinitions, boolean allowLimits) {
045        this.form = form;
046        this.formFieldDefinitions = formFieldDefinitions;
047        this.allowLimits = allowLimits;
048    }
049
050    protected BaseSimpleCommand(CommandSecurityDefinition commandSecurityDefinition,
051            List<FieldDefinition> formFieldDefinitions, boolean allowLimits) {
052        super(commandSecurityDefinition);
053        
054        init(form, formFieldDefinitions, allowLimits);
055    }
056    
057    protected BaseSimpleCommand(CommandSecurityDefinition commandSecurityDefinition, boolean allowLimits) {
058        super(commandSecurityDefinition);
059        
060        init(null, null, allowLimits);
061    }
062
063    @Override
064    protected void setupSession() {
065        super.setupSession();
066
067        if(form != null) {
068            session.setOptions(form.getOptions());
069            session.setTransferProperties(form.getTransferProperties());
070
071            if(allowLimits) {
072                session.setLimits(form.getLimits());
073            }
074        }
075    }
076
077    protected F getForm() {
078        return form;
079    }
080
081    protected List<FieldDefinition> getFormFieldDefinitions() {
082        return formFieldDefinitions;
083    }
084
085    protected void setupValidator(Validator validator) {
086        // Nothing.
087    }
088
089    protected ValidationResult validate(Validator validator) {
090        return validator.validate(form, getFormFieldDefinitions());
091    }
092
093    @Override
094    protected ValidationResult validate() {
095        ValidationResult validationResult = null;
096
097        if(getFormFieldDefinitions() != null) {
098            var validator = new Validator(this);
099
100            setupValidator(validator);
101            validationResult = validate(validator);
102        }
103
104        return validationResult;
105    }
106
107    protected void setupPreferredClobMimeType() {
108        var preferredClobMimeTypeName = form.getPreferredClobMimeTypeName();
109        
110        if(preferredClobMimeTypeName != null) {
111            var preferredClobMimeType = mimeTypeControl.getMimeTypeByName(preferredClobMimeTypeName);
112
113            if(preferredClobMimeType == null) {
114                addExecutionError(ExecutionErrors.UnknownPreferredClobMimeTypeName.name(), preferredClobMimeTypeName);
115            } else {
116                var preferredClobMimeTypeDetail = preferredClobMimeType.getLastDetail();
117                var entityAttributeTypeName = preferredClobMimeTypeDetail.getEntityAttributeType().getEntityAttributeTypeName();
118                
119                // Must be a CLOB and for now the preferred MIME type must be HTML.
120                if(!entityAttributeTypeName.equals(EntityAttributeTypes.CLOB.name())
121                        || !preferredClobMimeTypeDetail.getMimeTypeName().equals(MimeTypes.TEXT_HTML.mimeTypeName())) {
122                    addExecutionError(ExecutionErrors.InvalidPreferredClobMimeType.name(), preferredClobMimeTypeName, entityAttributeTypeName);
123                } else {
124                    session.setPreferredClobMimeType(preferredClobMimeType);
125                }
126            }
127        }
128    }
129    
130    private void initForRun(F form) {
131        this.form = form;
132    }
133
134    public <R extends BaseResult> Future<CommandResult<R>> runAsync(UserVisitPK userVisitPK, F form) {
135        initForRun(form);
136
137        return super.runAsync(userVisitPK);
138    }
139
140    public <R extends BaseResult> CommandResult<R> run(UserVisitPK userVisitPK, F form) {
141        initForRun(form);
142
143        return super.run(userVisitPK);
144    }
145
146    // Perform security and validation for GraphQL queries.
147    public boolean canQueryByGraphQl(UserVisitPK userVisitPK, F form) {
148        initForRun(form);
149        setUserVisitPK(userVisitPK);
150
151        initSession();
152
153        var securityResult = security();
154        var canQuery = false;
155
156        if(securityResult == null || !securityResult.getHasMessages()) {
157            var validationResult = validate();
158
159            if((validationResult == null || !validationResult.getHasErrors())) {
160                canQuery = true;
161            }
162        }
163
164        return canQuery;
165    }
166}