wip upload files and select
This commit is contained in:
@@ -42,10 +42,6 @@
|
|||||||
window.location = url;
|
window.location = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadComplete(e) {
|
|
||||||
records = e.detail;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher, getContext } from "svelte";
|
import { createEventDispatcher, getContext } from "svelte";
|
||||||
import Icon from "../common/Icon.svelte";
|
import Icon from "../common/Icon.svelte";
|
||||||
import Index from "../content/Index.svelte";
|
import FileIndex from "./FileIndex.svelte";
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
let dialogEl;
|
let dialogEl;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
const channel = getContext("channel");
|
const channel = getContext("channel");
|
||||||
$: data = {};
|
$: files = [];
|
||||||
let selectedRecords = [];
|
$: selectedRecords = [];
|
||||||
// onMount(() => {
|
// onMount(() => {
|
||||||
// load();
|
// load();
|
||||||
// });
|
// });
|
||||||
@@ -23,11 +22,11 @@
|
|||||||
selectedRecords = [];
|
selectedRecords = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function load(schema) {
|
function load(recordId) {
|
||||||
axios
|
fetch(channel.lucentUrl + "/records/files/?recordId=" + recordId)
|
||||||
.get(channel.lucentUrl + "/content/" + schema)
|
.then((response) => response.json())
|
||||||
.then((response) => {
|
.then((json) => {
|
||||||
data = response.data;
|
files = json;
|
||||||
})
|
})
|
||||||
.catch((error) => console.log(error));
|
.catch((error) => console.log(error));
|
||||||
}
|
}
|
||||||
@@ -37,7 +36,6 @@
|
|||||||
dispatch("insert", {
|
dispatch("insert", {
|
||||||
records: selectedRecords,
|
records: selectedRecords,
|
||||||
action: "insert",
|
action: "insert",
|
||||||
schema: data.schema.name,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,49 +47,47 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function open(schema) {
|
export function open(recordId) {
|
||||||
dialogEl.showModal();
|
dialogEl.showModal();
|
||||||
load(schema);
|
load(recordId);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<dialog bind:this={dialogEl}>
|
<dialog bind:this={dialogEl}>
|
||||||
{#if data.schema}
|
<div class="dialog-header">
|
||||||
<div class="dialog-header">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="button"
|
||||||
class="button"
|
on:click={insert}
|
||||||
on:click={insert}
|
disabled={selectedRecords.length === 0}
|
||||||
disabled={selectedRecords.length === 0}
|
>
|
||||||
>
|
Insert
|
||||||
Insert
|
</button>
|
||||||
</button>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="button"
|
||||||
class="button"
|
on:click={replace}
|
||||||
on:click={replace}
|
disabled={selectedRecords.length === 0}
|
||||||
disabled={selectedRecords.length === 0}
|
>
|
||||||
>
|
Replace
|
||||||
Replace
|
</button>
|
||||||
</button>
|
{#if selectedRecords.length > 0}
|
||||||
{#if selectedRecords.length > 0}
|
<span class="">
|
||||||
<span class="">
|
{selectedRecords.length} records selected
|
||||||
{selectedRecords.length} records selected
|
</span>
|
||||||
</span>
|
{/if}
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
on:click|preventDefault={close}
|
on:click|preventDefault={close}
|
||||||
type="button"
|
type="button"
|
||||||
class="button close"
|
class="button close"
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
>
|
>
|
||||||
<Icon icon="close"></Icon>
|
<Icon icon="close"></Icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dialog-body">
|
<div class="dialog-body">
|
||||||
<Index {...data} bind:selected={selectedRecords}></Index>
|
<FileIndex {files} bind:selected={selectedRecords}></FileIndex>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
import Icon from "../common/Icon.svelte";
|
||||||
|
import Checkbox from "../common/Checkbox.svelte";
|
||||||
|
import Preview from "../files/Preview.svelte";
|
||||||
|
import { fileurl } from "../files/imageserver";
|
||||||
|
|
||||||
|
const channel = getContext("channel");
|
||||||
|
|
||||||
|
export let files = [];
|
||||||
|
export let selected = [];
|
||||||
|
export let isWritable = true;
|
||||||
|
|
||||||
|
function eventToggleAll(e) {
|
||||||
|
selected = toggleAll(e, files, selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(file) {
|
||||||
|
selected = selectFile(file, selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toggleAll = (e, files, selected) => {
|
||||||
|
if (selected.length === files.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
e.currentTarget.checked = selected.length > 0;
|
||||||
|
return files;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const selectFile = (file, selected) => {
|
||||||
|
let fileExists = selected.find((r) => r.id === file.id);
|
||||||
|
if (fileExists) {
|
||||||
|
return selected.filter((r) => r.id !== file.id);
|
||||||
|
}
|
||||||
|
return [...selected, file];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="table mt-5">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{#if isWritable}
|
||||||
|
<th>
|
||||||
|
<Checkbox
|
||||||
|
value=""
|
||||||
|
on:change={eventToggleAll}
|
||||||
|
indeterminate={selected.length > 0 &&
|
||||||
|
selected.length < files.length}
|
||||||
|
checked={selected.length === files.length}
|
||||||
|
></Checkbox>
|
||||||
|
</th>
|
||||||
|
{/if}
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each files as file (file.id)}
|
||||||
|
<tr>
|
||||||
|
<td class="title-td">
|
||||||
|
<div class="title-td-contents">
|
||||||
|
{#if isWritable}
|
||||||
|
<Checkbox
|
||||||
|
on:change={() => select(file)}
|
||||||
|
checked={selected.find(
|
||||||
|
(s) => s.id === file.id,
|
||||||
|
)}
|
||||||
|
value={file}
|
||||||
|
></Checkbox>
|
||||||
|
{/if}
|
||||||
|
<div class="file-table-row">
|
||||||
|
<Preview
|
||||||
|
{file}
|
||||||
|
size={file.width > 0 ? "medium" : "small"}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{file.filename}
|
||||||
|
<span
|
||||||
|
>{(file.size / 1024).toFixed(1)}kB</span
|
||||||
|
>
|
||||||
|
|
||||||
|
{#if file.width > 0}
|
||||||
|
<span
|
||||||
|
>{file.width +
|
||||||
|
"x" +
|
||||||
|
file.height}</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
<a
|
||||||
|
href={fileurl(channel, file)}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<!-- <RecordRow
|
||||||
|
{record}
|
||||||
|
{graph}
|
||||||
|
{schema}
|
||||||
|
{visibleColumns}
|
||||||
|
{sortParam}
|
||||||
|
{sortField}
|
||||||
|
{users}
|
||||||
|
/> -->
|
||||||
|
<!-- <td>
|
||||||
|
<Avatar
|
||||||
|
name={usernameById(users, record._sys.updatedBy)}
|
||||||
|
side={24}
|
||||||
|
/>
|
||||||
|
</td> -->
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import Icon from "../common/Icon.svelte";
|
import Icon from "../common/Icon.svelte";
|
||||||
import {imgurl} from "./imageserver.js";
|
import { imgurl } from "./imageserver.js";
|
||||||
import {getContext} from "svelte";
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
export let record;
|
export let file;
|
||||||
const channel = getContext("channel");
|
const channel = getContext("channel");
|
||||||
export let size = "small";
|
export let size = "small";
|
||||||
export let showFilename = false;
|
export let showFilename = false;
|
||||||
@@ -28,50 +28,49 @@
|
|||||||
fontSize = "13";
|
fontSize = "13";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<div style="display: flex;align-items: center;gap: 5px;">
|
|
||||||
{#if record}
|
|
||||||
|
|
||||||
{#if record._file.mime.startsWith("image")}
|
<div style="display: flex;align-items: center;gap: 5px;">
|
||||||
|
{#if file}
|
||||||
|
{#if file.mime.startsWith("image")}
|
||||||
<!-- href={imgurl(record)} -->
|
<!-- href={imgurl(record)} -->
|
||||||
<a
|
<a
|
||||||
href="{channel.lucentUrl}/records/{record.id}"
|
href="{channel.lucentUrl}/files/{file.id}"
|
||||||
title={record._file.originalName}
|
title={file.filename}
|
||||||
style="width:{imageSide}px;height:{imageSide}px"
|
style="width:{imageSide}px;height:{imageSide}px"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
class="rounded w-100"
|
class="rounded w-100"
|
||||||
src={imgurl(channel,record)}
|
src={imgurl(channel, file)}
|
||||||
alt={record._file.path}
|
alt={file.path}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<a
|
<a
|
||||||
href="{channel.lucentUrl}/records/{record.id}"
|
href="{channel.lucentUrl}/files/{file.id}"
|
||||||
title={record._file.path}
|
title={file.path}
|
||||||
class="file-preview-small"
|
class="file-preview-small"
|
||||||
style="width:{imageSide}px;height:{imageSide}px"
|
style="width:{imageSide}px;height:{imageSide}px"
|
||||||
>
|
>
|
||||||
<Icon icon="file" width={fileSide} height={fileSide}/>
|
<Icon icon="file" width={fileSide} height={fileSide} />
|
||||||
<span class="ms-2"
|
<span class="ms-2"
|
||||||
>.{record._file.path.split(".").pop().toLowerCase()}</span
|
>.{file.path.split(".").pop().toLowerCase()}</span
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{#if showFilename}
|
{#if showFilename}
|
||||||
<a
|
<a
|
||||||
href="{channel.lucentUrl}/records/{record.id}"
|
href="{channel.lucentUrl}/files/{file.id}"
|
||||||
title={record._file.path}
|
title={file.path}
|
||||||
class="preview-file-filename lx-small-text text-decoration-none"
|
class="preview-file-filename lx-small-text text-decoration-none"
|
||||||
>{record._file.path} </a
|
>{file.path}
|
||||||
>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
img{
|
img {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,30 +1,29 @@
|
|||||||
export function imgurl(channel, record) {
|
export function imgurl(channel, file) {
|
||||||
if (record._file.mime === "image/svg+xml") {
|
if (file.mime === "image/svg+xml") {
|
||||||
return fileurl(channel, record);
|
return fileurl(channel, file);
|
||||||
|
}
|
||||||
|
return channel.filesUrl + `/thumbs/${file.path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fileurl(channel, file) {
|
||||||
|
return channel.filesUrl + `/${file.path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function htmlurl(channel, file, preset) {
|
||||||
|
let html = "";
|
||||||
|
let url = fileurl(channel, file);
|
||||||
|
|
||||||
|
if (file.width > 0) {
|
||||||
|
let presetUrl = url;
|
||||||
|
if (preset) {
|
||||||
|
presetUrl = channel.filesUrl + `/templates/${preset}/${file.path}`;
|
||||||
}
|
}
|
||||||
return channel.disks[record._file.disk] + `/thumbs/${record._file.path}`;
|
html = `<img src="${presetUrl}" alt="${file.path}" />`;
|
||||||
}
|
} else if (file.mime === "image/svg+xml") {
|
||||||
|
html = `<img src="${url}" alt="${file.path}"/>`;
|
||||||
export function fileurl(channel, record) {
|
} else {
|
||||||
return channel.disks[record._file.disk] + `/${record._file.path}`;
|
html = `<a href="${url}">${file.originalName}</a>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function htmlurl(channel, record, preset) {
|
return html;
|
||||||
|
|
||||||
let html = "";
|
|
||||||
let url = fileurl(channel, record)
|
|
||||||
|
|
||||||
if (record._file.width > 0) {
|
|
||||||
let presetUrl = url;
|
|
||||||
if (preset) {
|
|
||||||
presetUrl = channel.disks[record._file.disk] + `/templates/${preset}/${record._file.path}`;
|
|
||||||
}
|
|
||||||
html = `<img src="${presetUrl}" alt="${record._file.path}" />`
|
|
||||||
} else if (record._file.mime === "image/svg+xml") {
|
|
||||||
html = `<img src="${url}" alt="${record._file.path}"/>`
|
|
||||||
} else {
|
|
||||||
html = `<a href="${url}">${record._file.originalName}</a>`
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,6 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBrowseModal(e, schema) {
|
|
||||||
e.preventDefault();
|
|
||||||
browseModal.open(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function reorder(e) {
|
async function reorder(e) {
|
||||||
graph.edges = await sortByField(
|
graph.edges = await sortByField(
|
||||||
e.detail.source,
|
e.detail.source,
|
||||||
@@ -52,15 +47,15 @@
|
|||||||
function uploadComplete(e) {
|
function uploadComplete(e) {
|
||||||
records = e.detail;
|
records = e.detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openBrowseModal(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
browseModal.open(record.id);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mb-0">
|
<div class="mb-0">
|
||||||
<!-- <button
|
<button class="button" on:click={openBrowseModal}> Browse </button>
|
||||||
class="button"
|
|
||||||
on:click={(e) => openFileModal(e, collections[0].name)}
|
|
||||||
>
|
|
||||||
Browse
|
|
||||||
</button> -->
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Uploader recordId={record.id} on:uploadComplete={uploadComplete} />
|
<Uploader recordId={record.id} on:uploadComplete={uploadComplete} />
|
||||||
@@ -80,4 +75,4 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</Sortable>
|
</Sortable>
|
||||||
{/if} -->
|
{/if} -->
|
||||||
<!-- <FileDialog bind:this={browseModal} on:insert={insert}></FileDialog> -->
|
<FileDialog bind:this={browseModal} on:insert={insert}></FileDialog>
|
||||||
|
|||||||
@@ -28,18 +28,20 @@ final class Channel
|
|||||||
) {
|
) {
|
||||||
$this->lucentUrl = $url . "/lucent";
|
$this->lucentUrl = $url . "/lucent";
|
||||||
$this->filesUrl = $this->makeFilesUrl();
|
$this->filesUrl = $this->makeFilesUrl();
|
||||||
|
|
||||||
$this->previewTargetUrl = $url . "/" . $previewTarget;
|
$this->previewTargetUrl = $url . "/" . $previewTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function makeFilesUrl(): string
|
private function makeFilesUrl(): string
|
||||||
{
|
{
|
||||||
return match (config("filesystems.disks.lucent.driver")) {
|
$lucentDisk = config("lucent.disk");
|
||||||
"s3" => config("filesystems.disks.lucent.endpoint") .
|
return match (config("filesystems.disks.$lucentDisk.driver")) {
|
||||||
|
"s3" => config("filesystems.disks.$lucentDisk.endpoint") .
|
||||||
"/" .
|
"/" .
|
||||||
config("filesystems.disks.lucent.bucket"),
|
config("filesystems.disks.$lucentDisk.bucket"),
|
||||||
"local" => $this->url .
|
"local" => $this->url .
|
||||||
"/storage" .
|
"/storage" .
|
||||||
config("filesystems.disks.lucent.endpoint"),
|
config("filesystems.disks.$lucentDisk.endpoint"),
|
||||||
default => "",
|
default => "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ class SetupDatabase extends Command
|
|||||||
Blueprint $table,
|
Blueprint $table,
|
||||||
) {
|
) {
|
||||||
$table->uuid("id")->primary();
|
$table->uuid("id")->primary();
|
||||||
$table->uuid("record");
|
$table->uuid("recordId");
|
||||||
$table->string("name");
|
$table->string("filename");
|
||||||
$table->string("ogName");
|
$table->jsonb("captions");
|
||||||
$table->string("mime");
|
$table->string("mime");
|
||||||
$table->string("path");
|
$table->string("path");
|
||||||
$table->integer("size");
|
$table->integer("size");
|
||||||
@@ -122,7 +122,7 @@ class SetupDatabase extends Command
|
|||||||
});
|
});
|
||||||
|
|
||||||
DB::statement(
|
DB::statement(
|
||||||
"CREATE INDEX ON " . $this->prefix . "files (record)",
|
"CREATE INDEX ON " . $this->prefix . "files (recordId)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-2
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace Lucent\Data;
|
namespace Lucent\Data;
|
||||||
|
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
class File
|
class File
|
||||||
{
|
{
|
||||||
function __construct(
|
function __construct(
|
||||||
public readonly string $id,
|
public readonly string $id,
|
||||||
public readonly string $recordId,
|
public readonly string $recordId,
|
||||||
public readonly string $originalName,
|
public readonly string $filename,
|
||||||
public readonly string $mime,
|
public readonly string $mime,
|
||||||
public readonly string $path,
|
public readonly string $path,
|
||||||
public readonly int $size,
|
public readonly int $size,
|
||||||
@@ -21,7 +23,22 @@ class File
|
|||||||
return new File(
|
return new File(
|
||||||
id: data_get($data, "id"),
|
id: data_get($data, "id"),
|
||||||
recordId: data_get($data, "recordId"),
|
recordId: data_get($data, "recordId"),
|
||||||
originalName: data_get($data, "originalName"),
|
filename: data_get($data, "filename"),
|
||||||
|
mime: data_get($data, "mime"),
|
||||||
|
path: data_get($data, "path"),
|
||||||
|
size: data_get($data, "size"),
|
||||||
|
width: data_get($data, "width"),
|
||||||
|
height: data_get($data, "height"),
|
||||||
|
checksum: data_get($data, "checksum"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromDB(stdClass $data): File
|
||||||
|
{
|
||||||
|
return new File(
|
||||||
|
id: data_get($data, "id"),
|
||||||
|
recordId: data_get($data, "recordId"),
|
||||||
|
filename: data_get($data, "filename"),
|
||||||
mime: data_get($data, "mime"),
|
mime: data_get($data, "mime"),
|
||||||
path: data_get($data, "path"),
|
path: data_get($data, "path"),
|
||||||
size: data_get($data, "size"),
|
size: data_get($data, "size"),
|
||||||
@@ -35,4 +52,20 @@ class File
|
|||||||
{
|
{
|
||||||
return \json_decode(\json_encode($this), true);
|
return \json_decode(\json_encode($this), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toDB(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"id" => $this->id,
|
||||||
|
"recordId" => $this->recordId,
|
||||||
|
"filename" => $this->filename,
|
||||||
|
"mime" => $this->mime,
|
||||||
|
"path" => $this->path,
|
||||||
|
"size" => $this->size,
|
||||||
|
"width" => $this->width,
|
||||||
|
"height" => $this->height,
|
||||||
|
"checksum" => $this->checksum,
|
||||||
|
"captions" => "[]", // for the future
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\File;
|
||||||
|
|
||||||
|
use Lucent\Data\File as DataFile;
|
||||||
|
use Lucent\Database\Database;
|
||||||
|
use Lucent\Data\File;
|
||||||
|
|
||||||
|
class FileRepo
|
||||||
|
{
|
||||||
|
public function __construct() {}
|
||||||
|
|
||||||
|
public static function create(DataFile $file): void
|
||||||
|
{
|
||||||
|
Database::make()->table("lucent_files")->insert($file->toDB());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return File[]
|
||||||
|
*/
|
||||||
|
public static function byRecordId(string $recordId): array
|
||||||
|
{
|
||||||
|
return Database::make()
|
||||||
|
->table("lucent_files")
|
||||||
|
->where("recordId", $recordId)
|
||||||
|
->get()
|
||||||
|
->map(File::fromDB(...))
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,10 +85,10 @@ class FileService
|
|||||||
[$width, $height] = $this->isImage($mimetype)
|
[$width, $height] = $this->isImage($mimetype)
|
||||||
? getimagesize($file)
|
? getimagesize($file)
|
||||||
: [0, 0];
|
: [0, 0];
|
||||||
return new DataFile(
|
$dataFile = new DataFile(
|
||||||
id: Id::new(),
|
id: Id::new(),
|
||||||
recordId: $recordId,
|
recordId: $recordId,
|
||||||
originalName: $originalFilename,
|
filename: $originalFilename,
|
||||||
mime: $mimetype,
|
mime: $mimetype,
|
||||||
path: $path,
|
path: $path,
|
||||||
size: $file->getSize(),
|
size: $file->getSize(),
|
||||||
@@ -96,6 +96,9 @@ class FileService
|
|||||||
height: $height,
|
height: $height,
|
||||||
checksum: $checksum,
|
checksum: $checksum,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
FileRepo::create($dataFile);
|
||||||
|
return $dataFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFileName(
|
private function createFileName(
|
||||||
@@ -112,10 +115,11 @@ class FileService
|
|||||||
private function isImage(string $mimetype): bool
|
private function isImage(string $mimetype): bool
|
||||||
{
|
{
|
||||||
$imageMimes = [
|
$imageMimes = [
|
||||||
"image/webp",
|
|
||||||
"image/gif",
|
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
"image/png",
|
"image/png",
|
||||||
|
"image/avif",
|
||||||
|
"image/webp",
|
||||||
|
"image/gif",
|
||||||
"image/tiff",
|
"image/tiff",
|
||||||
];
|
];
|
||||||
return in_array($mimetype, $imageMimes);
|
return in_array($mimetype, $imageMimes);
|
||||||
@@ -156,4 +160,12 @@ class FileService
|
|||||||
$image = $originalImage->fit(300, 300);
|
$image = $originalImage->fit(300, 300);
|
||||||
$disk->put($thumbDir, $image->encode("webp", 75));
|
$disk->put($thumbDir, $image->encode("webp", 75));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DataFile[]
|
||||||
|
*/
|
||||||
|
public function filesForRecord(string $recordId): array
|
||||||
|
{
|
||||||
|
return FileRepo::byRecordId($recordId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use Lucent\Record\InputData\RecordInputData;
|
|||||||
use Lucent\Record\Manager;
|
use Lucent\Record\Manager;
|
||||||
use Lucent\Record\QueryRecord;
|
use Lucent\Record\QueryRecord;
|
||||||
use Lucent\Record\RecordService;
|
use Lucent\Record\RecordService;
|
||||||
|
use Lucent\File\FileService;
|
||||||
use Lucent\Record\Status;
|
use Lucent\Record\Status;
|
||||||
use Lucent\Schema\System;
|
use Lucent\Schema\System;
|
||||||
use Lucent\Schema\Ui\Reference;
|
use Lucent\Schema\Ui\Reference;
|
||||||
@@ -30,6 +31,7 @@ class RecordController extends Controller
|
|||||||
private readonly RecordService $recordService,
|
private readonly RecordService $recordService,
|
||||||
private readonly AccountService $accountService,
|
private readonly AccountService $accountService,
|
||||||
private readonly ChannelService $channelService,
|
private readonly ChannelService $channelService,
|
||||||
|
private readonly FileService $fileService,
|
||||||
private readonly Svelte $svelte,
|
private readonly Svelte $svelte,
|
||||||
private readonly Query $query,
|
private readonly Query $query,
|
||||||
private readonly Manager $recordManager,
|
private readonly Manager $recordManager,
|
||||||
@@ -493,4 +495,11 @@ class RecordController extends Controller
|
|||||||
}
|
}
|
||||||
return ok();
|
return ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function files(Request $request)
|
||||||
|
{
|
||||||
|
$recordId = $request->input("recordId");
|
||||||
|
|
||||||
|
return $this->fileService->filesForRecord($recordId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+117
-76
@@ -12,89 +12,130 @@ use Lucent\Http\Controller\RecordController;
|
|||||||
use Lucent\Http\Controller\RevisionController;
|
use Lucent\Http\Controller\RevisionController;
|
||||||
use Lucent\Http\Controller\SetupController;
|
use Lucent\Http\Controller\SetupController;
|
||||||
|
|
||||||
|
Route::get("/lucent/setup", [SetupController::class, "setup"]);
|
||||||
|
Route::get("/lfs-{disk}/{any}", [FileController::class, "fromDisk"])->where(
|
||||||
|
"any",
|
||||||
|
".*",
|
||||||
|
);
|
||||||
|
|
||||||
Route::get('/lucent/setup', [SetupController::class, 'setup']);
|
Route::group(
|
||||||
Route::get('/lfs-{disk}/{any}', [FileController::class, 'fromDisk'])->where('any', '.*');
|
[
|
||||||
|
"middleware" => ["web"],
|
||||||
|
"prefix" => "lucent",
|
||||||
|
],
|
||||||
|
function () {
|
||||||
|
Route::middleware(["lucent.guest"])->group(function () {
|
||||||
|
Route::get("/", [AuthController::class, "login"]);
|
||||||
|
|
||||||
|
Route::get("/register", [AuthController::class, "register"]);
|
||||||
|
Route::post("/register", [AuthController::class, "postRegister"]);
|
||||||
|
Route::get("/login", [AuthController::class, "login"]);
|
||||||
|
Route::post("/login", [AuthController::class, "postLogin"]);
|
||||||
|
Route::get("/verify", [AuthController::class, "verify"]);
|
||||||
|
Route::post("/verify", [AuthController::class, "postVerify"]);
|
||||||
|
});
|
||||||
|
|
||||||
Route::group([
|
Route::middleware("lucent.auth")->group(function () {
|
||||||
'middleware' => ['web'],
|
Route::get("/logout", [AuthController::class, "logout"]);
|
||||||
'prefix' => "lucent"
|
Route::get("/profile", [AccountController::class, "profile"]);
|
||||||
], function () {
|
Route::post("/account/update-name", [
|
||||||
|
AccountController::class,
|
||||||
|
"updateName",
|
||||||
|
]);
|
||||||
|
Route::post("/account/update-email", [
|
||||||
|
AccountController::class,
|
||||||
|
"updateEmail",
|
||||||
|
]);
|
||||||
|
Route::get("/command-report/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"report",
|
||||||
|
]);
|
||||||
|
Route::get("/command-report-source/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"reportSource",
|
||||||
|
]);
|
||||||
|
Route::post("/command/{signature}", [
|
||||||
|
BuildController::class,
|
||||||
|
"build",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
|
Route::get("/members/", [MemberController::class, "index"]);
|
||||||
|
Route::post("/members/invite", [MemberController::class, "invite"]);
|
||||||
|
Route::post("/members/update", [MemberController::class, "update"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::middleware(["lucent.auth"])
|
||||||
|
->prefix("/records")
|
||||||
|
->group(function () {
|
||||||
|
Route::get("/files", [RecordController::class, "files"]);
|
||||||
|
Route::get("/new", [RecordController::class, "new"]);
|
||||||
|
Route::get("/newInline", [
|
||||||
|
RecordController::class,
|
||||||
|
"newInline",
|
||||||
|
]);
|
||||||
|
Route::get("/suggestions", [
|
||||||
|
RecordController::class,
|
||||||
|
"suggestions",
|
||||||
|
]);
|
||||||
|
Route::get("/{rid}", [RecordController::class, "edit"]);
|
||||||
|
Route::post("/clone/{rid}", [RecordController::class, "clone"]);
|
||||||
|
// Route::get('/editInline/{rid}', [RecordController::class, 'editInline']);
|
||||||
|
Route::get("/{rid}/parents", [
|
||||||
|
RecordController::class,
|
||||||
|
"parents",
|
||||||
|
]);
|
||||||
|
Route::post("/", [RecordController::class, "save"]);
|
||||||
|
Route::post("/status/{status}", [
|
||||||
|
RecordController::class,
|
||||||
|
"status",
|
||||||
|
]);
|
||||||
|
Route::post("/delete", [RecordController::class, "delete"]);
|
||||||
|
Route::post("/{rid}/rollback/{version}", [
|
||||||
|
RecordController::class,
|
||||||
|
"rollback",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
Route::middleware(['lucent.guest'])->group(function () {
|
Route::middleware(["lucent.auth"])
|
||||||
Route::get('/', [AuthController::class, 'login']);
|
->prefix("/edges")
|
||||||
|
->group(function () {
|
||||||
|
Route::post("/insert-many", [
|
||||||
|
EdgeController::class,
|
||||||
|
"insertMany",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
Route::get('/register', [AuthController::class, 'register']);
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
Route::post('/register', [AuthController::class, 'postRegister']);
|
Route::get("/records/{rid}/revisions", [
|
||||||
Route::get('/login', [AuthController::class, 'login']);
|
RevisionController::class,
|
||||||
Route::post('/login', [AuthController::class, 'postLogin']);
|
"index",
|
||||||
Route::get('/verify', [AuthController::class, 'verify']);
|
]);
|
||||||
Route::post('/verify', [AuthController::class, 'postVerify']);
|
});
|
||||||
|
|
||||||
});
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
|
Route::get("/", [HomeController::class, "home"]);
|
||||||
|
Route::get("/home/records", [HomeController::class, "records"]);
|
||||||
|
});
|
||||||
|
|
||||||
Route::middleware('lucent.auth')->group(function () {
|
Route::middleware(["lucent.auth"])
|
||||||
Route::get('/logout', [AuthController::class, 'logout']);
|
->prefix("/content")
|
||||||
Route::get('/profile', [AccountController::class, 'profile']);
|
->group(function () {
|
||||||
Route::post('/account/update-name', [AccountController::class, 'updateName']);
|
Route::get("/{schemaName}", [RecordController::class, "index"]);
|
||||||
Route::post('/account/update-email', [AccountController::class, 'updateEmail']);
|
Route::get("/{schemaName}/csv", [
|
||||||
Route::get('/command-report/{signature}', [BuildController::class, 'report']);
|
RecordController::class,
|
||||||
Route::get('/command-report-source/{signature}', [BuildController::class, 'reportSource']);
|
"exportCSV",
|
||||||
Route::post('/command/{signature}', [BuildController::class, 'build']);
|
]);
|
||||||
});
|
Route::get("/{schemaName}/emptyTrash", [
|
||||||
|
RecordController::class,
|
||||||
|
"emptyTrash",
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
]);
|
||||||
Route::get('/members/', [MemberController::class, 'index']);
|
});
|
||||||
Route::post('/members/invite', [MemberController::class, 'invite']);
|
|
||||||
Route::post('/members/update', [MemberController::class, 'update']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/records")->group(function () {
|
|
||||||
|
|
||||||
Route::get('/new', [RecordController::class, 'new']);
|
|
||||||
Route::get('/newInline', [RecordController::class, 'newInline']);
|
|
||||||
Route::get('/suggestions', [RecordController::class, 'suggestions']);
|
|
||||||
Route::get('/{rid}', [RecordController::class, 'edit']);
|
|
||||||
Route::post('/clone/{rid}', [RecordController::class, 'clone']);
|
|
||||||
// Route::get('/editInline/{rid}', [RecordController::class, 'editInline']);
|
|
||||||
Route::get('/{rid}/parents', [RecordController::class, 'parents']);
|
|
||||||
Route::post('/', [RecordController::class, 'save']);
|
|
||||||
Route::post('/status/{status}', [RecordController::class, 'status']);
|
|
||||||
Route::post('/delete', [RecordController::class, 'delete']);
|
|
||||||
Route::post('/{rid}/rollback/{version}', [RecordController::class, 'rollback']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/edges")->group(function () {
|
|
||||||
Route::post('/insert-many', [EdgeController::class, 'insertMany']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
|
||||||
Route::get('/records/{rid}/revisions', [RevisionController::class, 'index']);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
|
||||||
Route::get('/', [HomeController::class, 'home']);
|
|
||||||
Route::get('/home/records', [HomeController::class, 'records']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/content")->group(function () {
|
|
||||||
Route::get('/{schemaName}', [RecordController::class, 'index']);
|
|
||||||
Route::get('/{schemaName}/csv', [RecordController::class, 'exportCSV']);
|
|
||||||
Route::get('/{schemaName}/emptyTrash', [RecordController::class, 'emptyTrash']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->group(function () {
|
|
||||||
Route::post('/files/upload', [FileController::class, 'upload']);
|
|
||||||
Route::get('/files/download', [FileController::class, 'download']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
Route::middleware(["lucent.auth"])->group(function () {
|
||||||
|
Route::post("/files/upload", [FileController::class, "upload"]);
|
||||||
|
Route::get("/files/download", [FileController::class, "download"]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user