mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Merged dev into feature/CE-1887-mobile-android-app
This commit is contained in:
@ -40,9 +40,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
** - alertType - name of entry in AlertType enum (ERROR, WARNING, SUCCESS)
|
||||
** - alertHtml - html to display inside the alert (other than its icon)
|
||||
*******************************************************************************/
|
||||
public class ProcessAlertWidget extends AbstractWidgetRenderer implements MetaDataProducerInterface<QWidgetMetaData>
|
||||
public class AlertWidgetRenderer extends AbstractWidgetRenderer implements MetaDataProducerInterface<QWidgetMetaData>
|
||||
{
|
||||
public static final String NAME = "ProcessAlertWidget";
|
||||
public static final String NAME = "AlertWidgetRenderer";
|
||||
|
||||
|
||||
|
@ -301,6 +301,9 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||
}
|
||||
}
|
||||
|
||||
widgetData.setAllowRecordEdit(BooleanUtils.isTrue(ValueUtils.getValueAsBoolean(input.getQueryParams().get("allowRecordEdit"))));
|
||||
widgetData.setAllowRecordDelete(BooleanUtils.isTrue(ValueUtils.getValueAsBoolean(input.getQueryParams().get("allowRecordDelete"))));
|
||||
|
||||
return (new RenderWidgetOutput(widgetData));
|
||||
}
|
||||
catch(Exception e)
|
||||
|
@ -28,7 +28,6 @@ import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -468,7 +467,8 @@ public class QValueFormatter
|
||||
{
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
Optional<FieldAdornment> fileDownloadAdornment = field.getAdornment(AdornmentType.FILE_DOWNLOAD);
|
||||
if(fileDownloadAdornment.isPresent())
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file name comes from: //
|
||||
@ -478,20 +478,7 @@ public class QValueFormatter
|
||||
// - tableLabel primaryKey fieldLabel //
|
||||
// - and - if the FILE_DOWNLOAD adornment had a DEFAULT_EXTENSION, then it gets added (preceded by a dot) //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Optional<FieldAdornment> fileDownloadAdornment = field.getAdornment(AdornmentType.FILE_DOWNLOAD);
|
||||
Map<String, Serializable> adornmentValues = Collections.emptyMap();
|
||||
|
||||
if(fileDownloadAdornment.isPresent())
|
||||
{
|
||||
adornmentValues = fileDownloadAdornment.get().getValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
///////////////////////////////////////////////////////
|
||||
// don't change blobs unless they are file-downloads //
|
||||
///////////////////////////////////////////////////////
|
||||
continue;
|
||||
}
|
||||
Map<String, Serializable> adornmentValues = fileDownloadAdornment.get().getValues();
|
||||
|
||||
String fileNameField = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FIELD));
|
||||
String fileNameFormat = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT));
|
||||
@ -542,7 +529,13 @@ public class QValueFormatter
|
||||
}
|
||||
}
|
||||
|
||||
record.setValue(field.getName(), "/data/" + table.getName() + "/" + primaryKey + "/" + field.getName() + "/" + fileName);
|
||||
/////////////////////////////////////////////
|
||||
// if field type is blob, update its value //
|
||||
/////////////////////////////////////////////
|
||||
if(QFieldType.BLOB.equals(field.getType()))
|
||||
{
|
||||
record.setValue(field.getName(), "/data/" + table.getName() + "/" + primaryKey + "/" + field.getName() + "/" + fileName);
|
||||
}
|
||||
record.setDisplayValue(field.getName(), fileName);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
public class StorageInput extends AbstractTableActionInput
|
||||
{
|
||||
private String reference;
|
||||
private String contentType;
|
||||
|
||||
|
||||
|
||||
@ -74,4 +75,35 @@ public class StorageInput extends AbstractTableActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for contentType
|
||||
*******************************************************************************/
|
||||
public String getContentType()
|
||||
{
|
||||
return (this.contentType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for contentType
|
||||
*******************************************************************************/
|
||||
public void setContentType(String contentType)
|
||||
{
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for contentType
|
||||
*******************************************************************************/
|
||||
public StorageInput withContentType(String contentType)
|
||||
{
|
||||
this.contentType = contentType;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
package com.kingsrook.qqq.backend.core.model.dashboard.widgets;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Model containing datastructure expected by frontend alert widget
|
||||
**
|
||||
@ -40,8 +43,10 @@ public class AlertData extends QWidgetData
|
||||
|
||||
|
||||
|
||||
private String html;
|
||||
private AlertType alertType;
|
||||
private String html;
|
||||
private AlertType alertType;
|
||||
private Boolean hideWidget = false;
|
||||
private List<String> bulletList;
|
||||
|
||||
|
||||
|
||||
@ -139,4 +144,66 @@ public class AlertData extends QWidgetData
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for hideWidget
|
||||
*******************************************************************************/
|
||||
public boolean getHideWidget()
|
||||
{
|
||||
return (this.hideWidget);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for hideWidget
|
||||
*******************************************************************************/
|
||||
public void setHideWidget(boolean hideWidget)
|
||||
{
|
||||
this.hideWidget = hideWidget;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for hideWidget
|
||||
*******************************************************************************/
|
||||
public AlertData withHideWidget(boolean hideWidget)
|
||||
{
|
||||
this.hideWidget = hideWidget;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for bulletList
|
||||
*******************************************************************************/
|
||||
public List<String> getBulletList()
|
||||
{
|
||||
return (this.bulletList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for bulletList
|
||||
*******************************************************************************/
|
||||
public void setBulletList(List<String> bulletList)
|
||||
{
|
||||
this.bulletList = bulletList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for bulletList
|
||||
*******************************************************************************/
|
||||
public AlertData withBulletList(List<String> bulletList)
|
||||
{
|
||||
this.bulletList = bulletList;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,9 +39,13 @@ public class ChildRecordListData extends QWidgetData
|
||||
private QueryOutput queryOutput;
|
||||
private QTableMetaData childTableMetaData;
|
||||
|
||||
private String tableName;
|
||||
private String tablePath;
|
||||
private String viewAllLink;
|
||||
private Integer totalRows;
|
||||
private Boolean disableRowClick = false;
|
||||
private Boolean allowRecordEdit = false;
|
||||
private Boolean allowRecordDelete = false;
|
||||
|
||||
private boolean canAddChildRecord = false;
|
||||
private Map<String, Serializable> defaultValuesForNewChildRecords;
|
||||
@ -352,4 +356,141 @@ public class ChildRecordListData extends QWidgetData
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return (this.tableName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
*******************************************************************************/
|
||||
public ChildRecordListData withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tablePath
|
||||
*******************************************************************************/
|
||||
public ChildRecordListData withTablePath(String tablePath)
|
||||
{
|
||||
this.tablePath = tablePath;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for disableRowClick
|
||||
*******************************************************************************/
|
||||
public Boolean getDisableRowClick()
|
||||
{
|
||||
return (this.disableRowClick);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for disableRowClick
|
||||
*******************************************************************************/
|
||||
public void setDisableRowClick(Boolean disableRowClick)
|
||||
{
|
||||
this.disableRowClick = disableRowClick;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for disableRowClick
|
||||
*******************************************************************************/
|
||||
public ChildRecordListData withDisableRowClick(Boolean disableRowClick)
|
||||
{
|
||||
this.disableRowClick = disableRowClick;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for allowRecordEdit
|
||||
*******************************************************************************/
|
||||
public Boolean getAllowRecordEdit()
|
||||
{
|
||||
return (this.allowRecordEdit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for allowRecordEdit
|
||||
*******************************************************************************/
|
||||
public void setAllowRecordEdit(Boolean allowRecordEdit)
|
||||
{
|
||||
this.allowRecordEdit = allowRecordEdit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for allowRecordEdit
|
||||
*******************************************************************************/
|
||||
public ChildRecordListData withAllowRecordEdit(Boolean allowRecordEdit)
|
||||
{
|
||||
this.allowRecordEdit = allowRecordEdit;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for allowRecordDelete
|
||||
*******************************************************************************/
|
||||
public Boolean getAllowRecordDelete()
|
||||
{
|
||||
return (this.allowRecordDelete);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for allowRecordDelete
|
||||
*******************************************************************************/
|
||||
public void setAllowRecordDelete(Boolean allowRecordDelete)
|
||||
{
|
||||
this.allowRecordDelete = allowRecordDelete;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for allowRecordDelete
|
||||
*******************************************************************************/
|
||||
public ChildRecordListData withAllowRecordDelete(Boolean allowRecordDelete)
|
||||
{
|
||||
this.allowRecordDelete = allowRecordDelete;
|
||||
return (this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -94,6 +94,29 @@ public class CountingHash<K extends Serializable> extends AbstractMap<K, Integer
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** increment the value for the specified key
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer put(K key)
|
||||
{
|
||||
return (add(key));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Set the value for the specified key by the supplied value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer put(K key, Integer value)
|
||||
{
|
||||
this.map.put(key, value);
|
||||
return (value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -35,9 +35,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for ProcessAlertWidget
|
||||
** Unit test for AlertWidgetRenderer
|
||||
*******************************************************************************/
|
||||
class ProcessAlertWidgetTest extends BaseTest
|
||||
class AlertWidgetRendererTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
@ -46,10 +46,10 @@ class ProcessAlertWidgetTest extends BaseTest
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(QContext.getQInstance(), ProcessAlertWidget.class.getPackageName());
|
||||
MetaDataProducerHelper.processAllMetaDataProducersInPackage(QContext.getQInstance(), AlertWidgetRenderer.class.getPackageName());
|
||||
|
||||
RenderWidgetInput input = new RenderWidgetInput();
|
||||
input.setWidgetMetaData(QContext.getQInstance().getWidget(ProcessAlertWidget.NAME));
|
||||
input.setWidgetMetaData(QContext.getQInstance().getWidget(AlertWidgetRenderer.NAME));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// make sure we run w/o exceptions (and w/ default outputs) if there are no query params //
|
@ -73,4 +73,19 @@ class CountingHashTest extends BaseTest
|
||||
assertEquals(1, alwaysMutable.get("B"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testPut()
|
||||
{
|
||||
CountingHash<String> alwaysMutable = new CountingHash<>(Map.of("A", 5));
|
||||
alwaysMutable.put("A", 25);
|
||||
assertEquals(25, alwaysMutable.get("A"));
|
||||
alwaysMutable.put("A");
|
||||
assertEquals(26, alwaysMutable.get("A"));
|
||||
}
|
||||
|
||||
}
|
@ -58,7 +58,7 @@ public class S3StorageAction extends AbstractS3Action implements QStorageInterfa
|
||||
|
||||
AmazonS3 amazonS3 = getS3Utils().getAmazonS3();
|
||||
String fullPath = getFullPath(storageInput);
|
||||
S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(amazonS3, backend.getBucketName(), fullPath);
|
||||
S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(amazonS3, backend.getBucketName(), fullPath, storageInput.getContentType());
|
||||
return (s3UploadOutputStream);
|
||||
}
|
||||
catch(Exception e)
|
||||
|
@ -53,6 +53,7 @@ public class S3UploadOutputStream extends OutputStream
|
||||
private final AmazonS3 amazonS3;
|
||||
private final String bucketName;
|
||||
private final String key;
|
||||
private final String contentType;
|
||||
|
||||
private byte[] buffer = new byte[5 * 1024 * 1024];
|
||||
private int offset = 0;
|
||||
@ -68,11 +69,12 @@ public class S3UploadOutputStream extends OutputStream
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public S3UploadOutputStream(AmazonS3 amazonS3, String bucketName, String key)
|
||||
public S3UploadOutputStream(AmazonS3 amazonS3, String bucketName, String key, String contentType)
|
||||
{
|
||||
this.amazonS3 = amazonS3;
|
||||
this.bucketName = bucketName;
|
||||
this.key = key;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
|
||||
@ -96,6 +98,13 @@ public class S3UploadOutputStream extends OutputStream
|
||||
*******************************************************************************/
|
||||
private void uploadIfNeeded()
|
||||
{
|
||||
ObjectMetadata objectMetadata = null;
|
||||
if(this.contentType != null)
|
||||
{
|
||||
objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(this.contentType);
|
||||
}
|
||||
|
||||
if(offset == buffer.length)
|
||||
{
|
||||
//////////////////////////////////////////
|
||||
@ -104,7 +113,8 @@ public class S3UploadOutputStream extends OutputStream
|
||||
if(initiateMultipartUploadResult == null)
|
||||
{
|
||||
LOG.info("Initiating a multipart upload", logPair("key", key));
|
||||
initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, key));
|
||||
initiateMultipartUploadResult = amazonS3.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, key, objectMetadata));
|
||||
|
||||
uploadPartResultList = new ArrayList<>();
|
||||
}
|
||||
|
||||
@ -115,7 +125,8 @@ public class S3UploadOutputStream extends OutputStream
|
||||
.withInputStream(new ByteArrayInputStream(buffer))
|
||||
.withBucketName(bucketName)
|
||||
.withKey(key)
|
||||
.withPartSize(buffer.length);
|
||||
.withPartSize(buffer.length)
|
||||
.withObjectMetadata(objectMetadata);
|
||||
|
||||
uploadPartResultList.add(amazonS3.uploadPart(uploadPartRequest));
|
||||
|
||||
@ -166,6 +177,13 @@ public class S3UploadOutputStream extends OutputStream
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectMetadata objectMetadata = null;
|
||||
if(this.contentType != null)
|
||||
{
|
||||
objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentType(this.contentType);
|
||||
}
|
||||
|
||||
if(initiateMultipartUploadResult != null)
|
||||
{
|
||||
if(offset > 0)
|
||||
@ -180,7 +198,8 @@ public class S3UploadOutputStream extends OutputStream
|
||||
.withInputStream(new ByteArrayInputStream(buffer, 0, offset))
|
||||
.withBucketName(bucketName)
|
||||
.withKey(key)
|
||||
.withPartSize(offset);
|
||||
.withPartSize(offset)
|
||||
.withObjectMetadata(objectMetadata);
|
||||
uploadPartResultList.add(amazonS3.uploadPart(uploadPartRequest));
|
||||
}
|
||||
|
||||
@ -193,8 +212,12 @@ public class S3UploadOutputStream extends OutputStream
|
||||
}
|
||||
else
|
||||
{
|
||||
if(objectMetadata == null)
|
||||
{
|
||||
objectMetadata = new ObjectMetadata();
|
||||
}
|
||||
|
||||
LOG.info("Putting object (non-multipart)", logPair("key", key), logPair("length", offset));
|
||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||
objectMetadata.setContentLength(offset);
|
||||
PutObjectResult putObjectResult = amazonS3.putObject(bucketName, key, new ByteArrayInputStream(buffer, 0, offset), objectMetadata);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ class S3UploadOutputStreamTest extends BaseS3Test
|
||||
outputStream.write("\n]\n".getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.close();
|
||||
|
||||
S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(getS3Utils().getAmazonS3(), bucketName, key);
|
||||
S3UploadOutputStream s3UploadOutputStream = new S3UploadOutputStream(getS3Utils().getAmazonS3(), bucketName, key, null);
|
||||
s3UploadOutputStream.write(outputStream.toByteArray(), 0, 5 * 1024 * 1024);
|
||||
s3UploadOutputStream.write(outputStream.toByteArray(), 0, 3 * 1024 * 1024);
|
||||
s3UploadOutputStream.write(outputStream.toByteArray(), 0, 3 * 1024 * 1024);
|
||||
|
Reference in New Issue
Block a user