lots
This commit is contained in:
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cp -r ./ ~/temp-lucent
|
||||||
|
cd ~/temp-lucent && npm run build
|
||||||
|
rm -rf ~/temp-lucent/node_modules
|
||||||
|
rm -rf ~/temp-lucent/.git
|
||||||
|
cd ~/
|
||||||
|
zip -r lucent.zip temp-lucent/
|
||||||
|
rm -rf ~/temp-lucent
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
php8.2 artisan serve --port 8197
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
php8.2 ./vendor/bin/phpstan analyse -c phpstan.neon
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"src/Response.php",
|
"src/Response.php",
|
||||||
"src/macros.php",
|
"src/macros.php",
|
||||||
"src/Schema/Functions.php",
|
|
||||||
"src/File/Uploader.php"
|
"src/File/Uploader.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import ErrorAlert from "../common/ErrorAlert.svelte";
|
import ErrorAlert from "../common/ErrorAlert.svelte";
|
||||||
import SpinnerButton from "../common/SpinnerButton.svelte";
|
import SpinnerButton from "../common/SpinnerButton.svelte";
|
||||||
|
import {getContext} from "svelte";
|
||||||
|
|
||||||
import Nav from "./Nav.svelte";
|
const channel = getContext("channel");
|
||||||
|
|
||||||
let name = "";
|
let name = "";
|
||||||
export let userCount = 1;
|
|
||||||
export let email = "";
|
export let email = "";
|
||||||
export let token = "";
|
|
||||||
let password = "";
|
|
||||||
let errorMessage = "";
|
let errorMessage = "";
|
||||||
|
|
||||||
function register(e) {
|
function register(e) {
|
||||||
@@ -16,15 +13,12 @@
|
|||||||
errorMessage = "";
|
errorMessage = "";
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.post("/register", {
|
.post(channel.lucentUrl + "/register", {
|
||||||
name: name,
|
name: name,
|
||||||
password: password,
|
|
||||||
email: email,
|
email: email,
|
||||||
token: token,
|
|
||||||
isAdmin: userCount === 0,
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
window.location = "/login";
|
window.location = channel.lucentUrl + "/login";
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
errorMessage = error.response?.data.error;
|
errorMessage = error.response?.data.error;
|
||||||
@@ -33,9 +27,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Nav active="Register"/>
|
|
||||||
<div class="wrapper-tiny">
|
<div class="wrapper-tiny">
|
||||||
{#if token || userCount === 0}
|
|
||||||
<ErrorAlert message={errorMessage}/>
|
<ErrorAlert message={errorMessage}/>
|
||||||
|
|
||||||
<form on:submit={register}>
|
<form on:submit={register}>
|
||||||
@@ -55,38 +47,13 @@
|
|||||||
bind:value={email}
|
bind:value={email}
|
||||||
class="form-control"
|
class="form-control"
|
||||||
id="email"
|
id="email"
|
||||||
disabled={userCount !== 0}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="password" class="form-label">Password</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
bind:value={password}
|
|
||||||
class="form-control"
|
|
||||||
id="password"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 form-check">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
class="form-check-input"
|
|
||||||
id="terms"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="terms"
|
|
||||||
>I Agree to the <a
|
|
||||||
href="https://www.radical-elements.com/terms-of-service"
|
|
||||||
target="_blank">terms and conditions</a
|
|
||||||
></label
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-center mt-5 d-block">
|
<div class="text-center mt-5 d-block">
|
||||||
<SpinnerButton label="Register"/>
|
<SpinnerButton label="Register"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{:else}
|
|
||||||
<p class="text-center mb-0">Registrations are currently closed</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
class="btn btn-sm btn-outline-primary">Make Draft
|
class="btn btn-sm btn-outline-primary">Make Draft
|
||||||
</button
|
</button
|
||||||
>
|
>
|
||||||
{#if filter["_sys.status_in"] === "trashed"}
|
{#if filter["status_in"] === "trashed"}
|
||||||
<button
|
<button
|
||||||
on:click|preventDefault={(e) => changeStatus(e, "published")}
|
on:click|preventDefault={(e) => changeStatus(e, "published")}
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
<RenderField {record} {schema} {graph} {field}/>
|
<RenderField {record} {schema} {graph} {field}/>
|
||||||
</td>
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
{#if schema.visible.includes("_sys.status")}
|
{#if schema.visible.includes("status")}
|
||||||
<td
|
<td
|
||||||
class="text-center"
|
class="text-center"
|
||||||
class:is-sort={"-_sys.status" == sort || "_sys.status" == sort}
|
class:is-sort={"-status" == sort || "status" == sort}
|
||||||
>
|
>
|
||||||
<Status status={record._sys.status}/>
|
<Status status={record.status}/>
|
||||||
</td>
|
</td>
|
||||||
{/if}
|
{/if}
|
||||||
{#if schema.visible.includes("_sys.createdBy")}
|
{#if schema.visible.includes("_sys.createdBy")}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
href="{channel.lucentUrl}/content/{schema.name}?filter[_sys.status_in]=trashed"
|
href="{channel.lucentUrl}/content/{schema.name}?filter[status_in]=trashed"
|
||||||
>View trashed records</a
|
>View trashed records</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export function sortByField(from, to, edges, fieldName) {
|
export function sortByField(from, to, edges, fieldName) {
|
||||||
|
console.log(from)
|
||||||
|
console.log(to)
|
||||||
if (from === to) {
|
if (from === to) {
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import Icon from "../common/Icon.svelte";
|
import Icon from "../common/Icon.svelte";
|
||||||
import {imgurl} from "../files/imageserver";
|
import {imgurl} from "../files/imageserver";
|
||||||
import {getContext} from "svelte";
|
import {getContext} from "svelte";
|
||||||
|
|
||||||
export let record;
|
export let record;
|
||||||
const channel = getContext("channel");
|
const channel = getContext("channel");
|
||||||
export let size = "small";
|
export let size = "small";
|
||||||
@@ -44,7 +45,6 @@
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- href="{channelurl}/files/download?schema={record._sys.schema}&path={record._file.path}" -->
|
|
||||||
<a
|
<a
|
||||||
href="{channel.lucentUrl}/records/{record.id}"
|
href="{channel.lucentUrl}/records/{record.id}"
|
||||||
title={record._file.path}
|
title={record._file.path}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
export let users;
|
export let users;
|
||||||
export let graph;
|
export let graph;
|
||||||
export let record;
|
export let record;
|
||||||
let schema = channel.schemas.find((s) => s.name === record._sys.schema);
|
let schema = channel.schemas.find((s) => s.name === record.schema);
|
||||||
let frieldlyUpdatedAt = formatDistanceToNow(
|
let frieldlyUpdatedAt = formatDistanceToNow(
|
||||||
parseJSON(record._sys.updatedAt),
|
parseJSON(record._sys.updatedAt),
|
||||||
{addSuffix: true}
|
{addSuffix: true}
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<Status status={record._sys.status}/>
|
<Status status={record.status}/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
export let record;
|
export let record;
|
||||||
export let schema;
|
export let schema;
|
||||||
export let isCreateMode;
|
export let isCreateMode;
|
||||||
export let active = "_default";
|
export let active = "";
|
||||||
|
|
||||||
let tabs = schema.fields.filter((f) => f.ui === "tab");
|
let tabs = schema.groups?.map((group) => {
|
||||||
|
return {label: group, name: group}
|
||||||
|
}) ?? [];
|
||||||
let mainTab = {
|
let mainTab = {
|
||||||
label: "Main",
|
label: "Main",
|
||||||
name: "_default",
|
name: "",
|
||||||
};
|
};
|
||||||
let graphTab = {
|
let graphTab = {
|
||||||
label: "Graph",
|
label: "Graph",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
export let isCreateMode;
|
export let isCreateMode;
|
||||||
export let users;
|
export let users;
|
||||||
let originalContent;
|
let originalContent;
|
||||||
let activeContentTab = "_default";
|
let activeContentTab = "";
|
||||||
let recordGraph = null;
|
let recordGraph = null;
|
||||||
$: hasUnsavedData = false;
|
$: hasUnsavedData = false;
|
||||||
$: validationErrors = null;
|
$: validationErrors = null;
|
||||||
@@ -38,16 +38,6 @@
|
|||||||
(f) => f.name !== "id"
|
(f) => f.name !== "id"
|
||||||
);
|
);
|
||||||
|
|
||||||
let tabname = "_default";
|
|
||||||
let fieldToTabs = schema.fields.reduce((c, f) => {
|
|
||||||
if (f.ui === "tab") {
|
|
||||||
tabname = f.name;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
c[tabname] = [...(c[tabname] ?? []), f.name];
|
|
||||||
return c;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
setOriginalContent();
|
setOriginalContent();
|
||||||
@@ -56,6 +46,8 @@
|
|||||||
function setOriginalContent() {
|
function setOriginalContent() {
|
||||||
originalContent = {
|
originalContent = {
|
||||||
data: JSON.parse(JSON.stringify(record.data)),
|
data: JSON.parse(JSON.stringify(record.data)),
|
||||||
|
schema: record.schema,
|
||||||
|
status: record.status,
|
||||||
_sys: JSON.parse(JSON.stringify(record._sys)),
|
_sys: JSON.parse(JSON.stringify(record._sys)),
|
||||||
_file: JSON.parse(JSON.stringify(record._file)),
|
_file: JSON.parse(JSON.stringify(record._file)),
|
||||||
edges: JSON.parse(JSON.stringify(graph.edges)),
|
edges: JSON.parse(JSON.stringify(graph.edges)),
|
||||||
@@ -88,6 +80,8 @@
|
|||||||
}
|
}
|
||||||
return !isEqual(originalContent, {
|
return !isEqual(originalContent, {
|
||||||
data: record.data,
|
data: record.data,
|
||||||
|
schema: record.schema,
|
||||||
|
status: record.status,
|
||||||
_sys: record._sys,
|
_sys: record._sys,
|
||||||
_file: record._file,
|
_file: record._file,
|
||||||
edges: graph.edges,
|
edges: graph.edges,
|
||||||
@@ -170,7 +164,7 @@
|
|||||||
<div
|
<div
|
||||||
class="d-flex mt-4 mb-3 align-items-center justify-content-center"
|
class="d-flex mt-4 mb-3 align-items-center justify-content-center"
|
||||||
>
|
>
|
||||||
<StatusSelect bind:status={record._sys.status} {schema}/>
|
<StatusSelect bind:status={record.status} {schema}/>
|
||||||
{#if isCreateMode}
|
{#if isCreateMode}
|
||||||
<button
|
<button
|
||||||
class="ms-2 btn btn-primary btn-spinner"
|
class="ms-2 btn btn-primary btn-spinner"
|
||||||
@@ -215,7 +209,7 @@
|
|||||||
<FilePreview {record} {schema}/>
|
<FilePreview {record} {schema}/>
|
||||||
<!-- <fieldset disabled="disabled"> -->
|
<!-- <fieldset disabled="disabled"> -->
|
||||||
{#each activeFields as field (field.name)}
|
{#each activeFields as field (field.name)}
|
||||||
{#if fieldToTabs[activeContentTab].includes(field.name)}
|
{#if activeContentTab === field.group}
|
||||||
<FormField
|
<FormField
|
||||||
bind:data={record.data}
|
bind:data={record.data}
|
||||||
bind:graph={graph}
|
bind:graph={graph}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
if (!carry[schemaField]) {
|
if (!carry[schemaField]) {
|
||||||
carry[schemaField] = {
|
carry[schemaField] = {
|
||||||
field: channel.schemas
|
field: channel.schemas
|
||||||
.find((s) => s.name === record._sys.schema)
|
.find((s) => s.name === record.schema)
|
||||||
.fields.find((f) => f.name === edge.field),
|
.fields.find((f) => f.name === edge.field),
|
||||||
nodes: [],
|
nodes: [],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
selectedRevision?._sys.version}
|
selectedRevision?._sys.version}
|
||||||
>
|
>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<Status status={revision._sys.status}/>
|
<Status status={revision.status}/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">version {revision._sys.version}</div>
|
<div class="col-2">version {revision._sys.version}</div>
|
||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
function setOriginalContent() {
|
function setOriginalContent() {
|
||||||
originalContent = {
|
originalContent = {
|
||||||
data: JSON.parse(JSON.stringify(record.data)),
|
data: JSON.parse(JSON.stringify(record.data)),
|
||||||
|
schema: record.schema,
|
||||||
|
status: record.status,
|
||||||
_sys: JSON.parse(JSON.stringify(record._sys)),
|
_sys: JSON.parse(JSON.stringify(record._sys)),
|
||||||
_file: JSON.parse(JSON.stringify(record._file)),
|
_file: JSON.parse(JSON.stringify(record._file)),
|
||||||
edges: JSON.parse(JSON.stringify(graph.edges)),
|
edges: JSON.parse(JSON.stringify(graph.edges)),
|
||||||
@@ -81,6 +83,8 @@
|
|||||||
}
|
}
|
||||||
return !isEqual(originalContent, {
|
return !isEqual(originalContent, {
|
||||||
data: record.data,
|
data: record.data,
|
||||||
|
schema: record.schema,
|
||||||
|
status: record.status,
|
||||||
_sys: record._sys,
|
_sys: record._sys,
|
||||||
_file: record._file,
|
_file: record._file,
|
||||||
edges: graph.edges,
|
edges: graph.edges,
|
||||||
@@ -181,7 +185,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="d-flex mt-3 align-items-center justify-content-center">
|
<div class="d-flex mt-3 align-items-center justify-content-center">
|
||||||
{#if schema.hasDrafts}
|
{#if schema.hasDrafts}
|
||||||
<StatusSelect bind:status={record._sys.status} {schema}/>
|
<StatusSelect bind:status={record.status} {schema}/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if isCreateMode}
|
{#if isCreateMode}
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Mustache from "mustache";
|
|||||||
import {stripHtml} from "../../helpers";
|
import {stripHtml} from "../../helpers";
|
||||||
|
|
||||||
export function previewTitle(schemas, record, graph) {
|
export function previewTitle(schemas, record, graph) {
|
||||||
let schema = schemas.find((aschema) => aschema.name === record?._sys.schema);
|
let schema = schemas.find((aschema) => aschema.name === record?.schema);
|
||||||
|
|
||||||
if (!schema?.titleTemplate) {
|
if (!schema?.titleTemplate) {
|
||||||
return noTemplate(schema, record);
|
return noTemplate(schema, record);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
export let classes = "";
|
export let classes = "";
|
||||||
export let hasDelete = false;
|
export let hasDelete = false;
|
||||||
|
|
||||||
let schema = channel.schemas.find((aschema) => aschema.name === record._sys.schema);
|
let schema = channel.schemas.find((aschema) => aschema.name === record.schema);
|
||||||
let cardTitle = previewTitle(channel.schemas, record, graph);
|
let cardTitle = previewTitle(channel.schemas, record, graph);
|
||||||
function remove(e) {
|
function remove(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
{schema.label}
|
{schema.label}
|
||||||
</small>
|
</small>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
{#if record._sys.status === "draft"}
|
{#if record.status === "draft"}
|
||||||
<Status status={record._sys.status} />
|
<Status status={record.status} />
|
||||||
{/if}
|
{/if}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
export let schemas;
|
export let schemas;
|
||||||
export let record;
|
export let record;
|
||||||
let editRecord;
|
let editRecord;
|
||||||
let schema = schemas.find((aschema) => aschema.name === record._sys.schema);
|
let schema = schemas.find((aschema) => aschema.name === record.schema);
|
||||||
$: editMode = false;
|
$: editMode = false;
|
||||||
$: expanded = false;
|
$: expanded = false;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
const channel = getContext("channel");
|
const channel = getContext("channel");
|
||||||
export let record;
|
export let record;
|
||||||
export let graph;
|
export let graph;
|
||||||
$: schema = channel.schemas.find((aschema) => aschema.name === record._sys.schema);
|
$: schema = channel.schemas.find((aschema) => aschema.name === record.schema);
|
||||||
|
|
||||||
$: title = previewTitle(channel.schemas, record, graph);
|
$: title = previewTitle(channel.schemas, record, graph);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Status from "./Status.svelte";
|
import Status from "./Status.svelte";
|
||||||
import {getStatus, getStatusList} from "./StatusText";
|
import {getStatus, getStatusList} from "./StatusText";
|
||||||
|
|
||||||
export let status;
|
export let status = "draft";
|
||||||
export let schema;
|
export let schema;
|
||||||
let dropdown;
|
let dropdown;
|
||||||
$: currentStatus = getStatus(status);
|
$: currentStatus = getStatus(status);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
const action = e.detail.action;
|
const action = e.detail.action;
|
||||||
let newEdges = recordsToInsert.map((r) => {
|
let newEdges = recordsToInsert.map((r) => {
|
||||||
return {
|
return {
|
||||||
schema: r._sys.schema,
|
schema: r.schema,
|
||||||
target: r.data.id,
|
target: r.data.id,
|
||||||
source: record.data.id,
|
source: record.data.id,
|
||||||
field: field.name,
|
field: field.name,
|
||||||
|
|||||||
@@ -36,7 +36,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function reorder(e) {
|
async function reorder(e) {
|
||||||
graph.edges = await sortByField(e.detail.from, e.detail.to, graph.edges, field.name);
|
console.log(e.detail)
|
||||||
|
graph.edges = await sortByField(e.detail.source, e.detail.target, graph.edges, field.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insert(e) {
|
function insert(e) {
|
||||||
@@ -48,8 +49,8 @@
|
|||||||
return {
|
return {
|
||||||
target: r.id,
|
target: r.id,
|
||||||
source: record.id,
|
source: record.id,
|
||||||
sourceSchema: record._sys.schema,
|
sourceSchema: record.schema,
|
||||||
targetSchema: r._sys.schema,
|
targetSchema: r.schema,
|
||||||
field: field.name,
|
field: field.name,
|
||||||
rank: ""
|
rank: ""
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
return {
|
return {
|
||||||
target: r.id,
|
target: r.id,
|
||||||
source: record.id,
|
source: record.id,
|
||||||
sourceSchema: record._sys.schema,
|
sourceSchema: record.schema,
|
||||||
targetSchema: r._sys.schema,
|
targetSchema: r.schema,
|
||||||
field: field.name,
|
field: field.name,
|
||||||
rank: ""
|
rank: ""
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -74,8 +74,8 @@
|
|||||||
return {
|
return {
|
||||||
target: r.id,
|
target: r.id,
|
||||||
source: record.id,
|
source: record.id,
|
||||||
sourceSchema: record._sys.schema,
|
sourceSchema: record.schema,
|
||||||
targetSchema: r._sys.schema,
|
targetSchema: r.schema,
|
||||||
field: field.name,
|
field: field.name,
|
||||||
rank: ""
|
rank: ""
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,8 +54,8 @@
|
|||||||
return {
|
return {
|
||||||
target: r.id,
|
target: r.id,
|
||||||
source: record.id,
|
source: record.id,
|
||||||
sourceSchema: record._sys.schema,
|
sourceSchema: record.schema,
|
||||||
targetSchema: r._sys.schema,
|
targetSchema: r.schema,
|
||||||
field: field.name,
|
field: field.name,
|
||||||
rank: ""
|
rank: ""
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\AccessKey;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Member\Role;
|
|
||||||
|
|
||||||
class AccessKey
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public readonly string $_id,
|
|
||||||
public readonly string $name,
|
|
||||||
public readonly Role $role,
|
|
||||||
public readonly string $token,
|
|
||||||
private readonly ?string $showOnceToken = null,
|
|
||||||
) {
|
|
||||||
$validator = Validator::make($this->toArray(), [
|
|
||||||
'name' => 'min:3,max:120',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($validator->fails()) {
|
|
||||||
throw new LucentException($validator->errors()->first());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function fromArray(array $data): AccessKey
|
|
||||||
{
|
|
||||||
|
|
||||||
return new AccessKey(
|
|
||||||
_id: data_get($data, "_id"),
|
|
||||||
name: data_get($data, "name"),
|
|
||||||
role: Role::from(data_get($data, "role")),
|
|
||||||
token: data_get($data, "token"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getShowOnceToken(): ?string
|
|
||||||
{
|
|
||||||
return $this->showOnceToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isValid(string $token): bool
|
|
||||||
{
|
|
||||||
return Hash::check($token, $this->token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($this), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\AccessKey;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Lucent\Channel\ChannelContext;
|
|
||||||
use Lucent\DB\Monger;
|
|
||||||
|
|
||||||
class AccessKeyRepo
|
|
||||||
{
|
|
||||||
|
|
||||||
public static function findByToken(string $token): ?AccessKey
|
|
||||||
{
|
|
||||||
$channel = ChannelContext::get()->channel;
|
|
||||||
return $channel->accessKeys->firstWhere("token",$token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function add(AccessKey $accessKey): void
|
|
||||||
{
|
|
||||||
$channel = ChannelContext::get()->channel;
|
|
||||||
Monger::central()->updateOne("channels", ["_id" => $channel->_id], [
|
|
||||||
'$push' => [
|
|
||||||
"accessKeys" => $accessKey->toArray()
|
|
||||||
],
|
|
||||||
'$set' => [
|
|
||||||
"updatedAt" => Carbon::now()->toJson(),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function remove(string $id): void
|
|
||||||
{
|
|
||||||
$channel = ChannelContext::get()->channel;
|
|
||||||
Monger::central()->updateOne("channels", ["_id" => $channel->_id], [
|
|
||||||
'$pull' => [
|
|
||||||
"accessKeys" => ["_id" => $id]
|
|
||||||
],
|
|
||||||
'$set' => [
|
|
||||||
"updatedAt" => Carbon::now()->toJson(),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\AccessKey;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Lucent\Id\Id;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Member\Role;
|
|
||||||
|
|
||||||
class AccessKeyService
|
|
||||||
{
|
|
||||||
|
|
||||||
public static function create(string $name, string $role): AccessKey
|
|
||||||
{
|
|
||||||
$showOnceToken = Str::random(48);
|
|
||||||
$accessKey = new AccessKey(
|
|
||||||
_id: Id::new(),
|
|
||||||
name: $name,
|
|
||||||
token: hash("sha256", $showOnceToken),
|
|
||||||
role: Role::from($role),
|
|
||||||
showOnceToken: $showOnceToken,
|
|
||||||
);
|
|
||||||
|
|
||||||
AccessKeyRepo::add($accessKey);
|
|
||||||
return $accessKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findByToken(string $token): ?AccessKey
|
|
||||||
{
|
|
||||||
$hashedToken = hash("sha256", $token);
|
|
||||||
return AccessKeyRepo::findByToken($hashedToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function remove(string $id): void
|
|
||||||
{
|
|
||||||
|
|
||||||
AccessKeyRepo::remove($id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\AccessKey;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @extends \Illuminate\Support\Collection<int|string, AccessKey>
|
|
||||||
*/
|
|
||||||
final class AccessKeysCollection extends Collection
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
AccessKey ...$array
|
|
||||||
) {
|
|
||||||
parent::__construct($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return AccessKey[]
|
|
||||||
**/
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return collect($this)->values()->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function toDB(): array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function fromArray(array $data): AccessKeysCollection
|
|
||||||
{
|
|
||||||
$item = array_map([AccessKey::class, 'fromArray'], $data);
|
|
||||||
return new AccessKeysCollection(...$item);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\AccessKey;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Lucent\Account\Role;
|
|
||||||
|
|
||||||
class ApiMiddleware
|
|
||||||
{
|
|
||||||
|
|
||||||
public function handle(Request $request, Closure $next, string $accessLevel): Response
|
|
||||||
{
|
|
||||||
|
|
||||||
$bearerToken = $request->header('Authorization');
|
|
||||||
$token = str_replace('Bearer ', '', $bearerToken);
|
|
||||||
|
|
||||||
$role = match ($token) {
|
|
||||||
config("lucent.read_key") => Role::READER,
|
|
||||||
config("lucent.write_key") => Role::EDITOR,
|
|
||||||
config("lucent.developer_key") => Role::DEVELOPER,
|
|
||||||
default => ""
|
|
||||||
};
|
|
||||||
|
|
||||||
if (empty($role)) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!$role->hasAccess($accessLevel)) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->mergeIfMissing(['userId' => "system"]);
|
|
||||||
$request->mergeIfMissing(['userRole' => $role->value]);
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,6 +23,12 @@ readonly class AccountService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function countUsers(): int
|
||||||
|
{
|
||||||
|
return $this->userRepo->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection<UserProfile>
|
* @return Collection<UserProfile>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -154,5 +154,18 @@ readonly class AuthService
|
|||||||
return $user;
|
return $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws LucentException
|
||||||
|
*/
|
||||||
|
public function registerAdmin(
|
||||||
|
string $name,
|
||||||
|
string $email
|
||||||
|
): User
|
||||||
|
{
|
||||||
|
$user = $this->invite($name, $email, "admin");
|
||||||
|
$this->sendLoginEmail($user->email);
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,21 @@ final class ChannelService
|
|||||||
|
|
||||||
public static function fromConfig(): ChannelService
|
public static function fromConfig(): ChannelService
|
||||||
{
|
{
|
||||||
|
if(file_exists(storage_path("lucent.config.json"))){
|
||||||
$configJson = file_get_contents(storage_path("lucent.config.json"));
|
$configJson = file_get_contents(storage_path("lucent.config.json"));
|
||||||
$configArray = json_decode($configJson, true);
|
$configArray = json_decode($configJson, true);
|
||||||
|
}else{
|
||||||
|
$configArray = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$schemaService = new SchemaService();
|
$schemaService = new SchemaService();
|
||||||
$schemasCollection = (new Collection($configArray["schemas"]))->map([$schemaService, 'fromArray']);
|
$schemasCollection = (new Collection($configArray["schemas"] ?? []))->map([$schemaService, 'fromArray']);
|
||||||
|
|
||||||
|
|
||||||
$channel = new Channel(
|
$channel = new Channel(
|
||||||
name: $configArray["name"],
|
name: $configArray["name"] ?? "",
|
||||||
url: rtrim($configArray["url"], "/"),
|
url: rtrim($configArray["url"] ?? "", "/"),
|
||||||
schemas: $schemasCollection,
|
schemas: $schemasCollection,
|
||||||
imageFilters: $configArray["imageFilters"] ?? [],
|
imageFilters: $configArray["imageFilters"] ?? [],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Illuminate\Console\Command;
|
|||||||
class CompileConfig extends Command
|
class CompileConfig extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $signature = 'lucent:compile:config {path}';
|
protected $signature = 'lucent:config';
|
||||||
|
|
||||||
protected $description = 'Compiles Config';
|
protected $description = 'Compiles Config';
|
||||||
|
|
||||||
@@ -21,18 +21,18 @@ class CompileConfig extends Command
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$configDir = base_path($this->argument('path'));
|
$configDir = base_path(config('lucent.config_path'));
|
||||||
|
|
||||||
$configJson = file_get_contents($configDir . "lucent.json");
|
$configJson = file_get_contents($configDir . "/lucent.json");
|
||||||
$config = json_decode($configJson, true);
|
$config = json_decode($configJson, true);
|
||||||
$schemasDirIterator = new DirectoryIterator($configDir . "Schemas");
|
$schemasDirIterator = new DirectoryIterator($configDir . "/Schemas");
|
||||||
$schemas = [];
|
$schemas = [];
|
||||||
foreach ($schemasDirIterator as $file) {
|
foreach ($schemasDirIterator as $file) {
|
||||||
if ($file->getExtension() !== "json") {
|
if ($file->getExtension() !== "json") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$schemaJson = file_get_contents($configDir . "Schemas/" . $file->getFilename());
|
$schemaJson = file_get_contents($configDir . "/Schemas/" . $file->getFilename());
|
||||||
$schema = json_decode($schemaJson, true);
|
$schema = json_decode($schemaJson, true);
|
||||||
if (empty($schema)) {
|
if (empty($schema)) {
|
||||||
$this->error("Invalid JSON " . $file->getFilename());
|
$this->error("Invalid JSON " . $file->getFilename());
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ class RebuildThumbnails extends Command
|
|||||||
$filesDir = storage_path("app/public/" . $schema->path . "/");
|
$filesDir = storage_path("app/public/" . $schema->path . "/");
|
||||||
$thumbDir = storage_path("app/public/thumbs/" . $schema->path . "/");
|
$thumbDir = storage_path("app/public/thumbs/" . $schema->path . "/");
|
||||||
if (!file_exists($thumbDir)) {
|
if (!file_exists($thumbDir)) {
|
||||||
mkdir($thumbDir);
|
make_dir_r($thumbDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($filesDir)) {
|
||||||
|
make_dir_r($filesDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
$filesDirIterator = new DirectoryIterator($filesDir);
|
$filesDirIterator = new DirectoryIterator($filesDir);
|
||||||
|
|||||||
+1
-6
@@ -1,11 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"view" => [
|
"config_path" => env("LUCENT_CONFIG_PATH", "app/Lucent")
|
||||||
"image_server" => env("LUCENT_IMAGE_SERVER")
|
|
||||||
],
|
|
||||||
"read_key" => env("LUCENT_READ_KEY"),
|
|
||||||
"write_key" => env("LUCENT_WRITE_KEY"),
|
|
||||||
"developer_key" => env("LUCENT_DEVELOPER_KEY")
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
$table->uuid("id")->primary();
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
$table->string('email')->unique();
|
||||||
|
$table->string('role');
|
||||||
|
$table->string('createdAt');
|
||||||
|
$table->string('updatedAt');
|
||||||
|
$table->string('loggedInAt');
|
||||||
|
$table->string('mailToken')->nullable();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('sessions', function (Blueprint $table) {
|
||||||
|
$table->string('id')->primary();
|
||||||
|
$table->foreignId('user_id')->nullable()->index();
|
||||||
|
$table->string('ip_address', 45)->nullable();
|
||||||
|
$table->text('user_agent')->nullable();
|
||||||
|
$table->longText('payload');
|
||||||
|
$table->integer('last_activity')->index();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('sessions');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('records', function (Blueprint $table) {
|
||||||
|
$table->uuid('id')->primary();
|
||||||
|
$table->string('schema');
|
||||||
|
$table->string('status');
|
||||||
|
$table->json('data');
|
||||||
|
$table->json('_sys');
|
||||||
|
$table->json('_file');
|
||||||
|
|
||||||
|
$table->index(['schema', 'status']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('edges', function (Blueprint $table) {
|
||||||
|
$table->uuid('source');
|
||||||
|
$table->uuid('target');
|
||||||
|
$table->string('sourceSchema');
|
||||||
|
$table->string('targetSchema');
|
||||||
|
$table->string('field');
|
||||||
|
$table->string('rank');
|
||||||
|
|
||||||
|
$table->unique(['source', 'target', "field"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('records');
|
||||||
|
Schema::dropIfExists('edges');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('revisions', function (Blueprint $table) {
|
||||||
|
$table->uuid('id')->primary();
|
||||||
|
$table->uuid('recordId');
|
||||||
|
$table->string('schema');
|
||||||
|
$table->json('data');
|
||||||
|
$table->json('_sys');
|
||||||
|
$table->json('_file');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('revisions');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use Lucent\LucentException;
|
|
||||||
|
|
||||||
class Field
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param string[] $collections
|
|
||||||
*/
|
|
||||||
function __construct(
|
|
||||||
public FieldName $name,
|
|
||||||
public string $label,
|
|
||||||
public string $ui,
|
|
||||||
public string $help = "",
|
|
||||||
public bool $trashed = false,
|
|
||||||
public bool $locked = false,
|
|
||||||
public string $regex = "",
|
|
||||||
public string $mime = "",
|
|
||||||
public bool $readonly = false,
|
|
||||||
public bool $nullable = false,
|
|
||||||
public bool $required = false,
|
|
||||||
public int $decimals = 0,
|
|
||||||
public array $collections = [],
|
|
||||||
public mixed $min = null,
|
|
||||||
public mixed $max = null,
|
|
||||||
public mixed $default = null,
|
|
||||||
public string $optionsFrom = "",
|
|
||||||
public string $optionsField = "",
|
|
||||||
public bool $optionsSuggest = true,
|
|
||||||
public bool $unique = false, // not used
|
|
||||||
public string $layout = "",
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public static function fromArray(array $data): Field
|
|
||||||
{
|
|
||||||
return new Field(
|
|
||||||
name: new FieldName($data["name"]),
|
|
||||||
label:$data["label"],
|
|
||||||
ui: $data["ui"],
|
|
||||||
help:$data["help"] ?? "",
|
|
||||||
trashed:$data["trashed"] ?? false,
|
|
||||||
locked:$data["locked"] ?? false,
|
|
||||||
regex:$data["regex"] ?? "" ,
|
|
||||||
mime:$data["mime"] ?? "" ,
|
|
||||||
readonly:$data["readonly"] ?? false,
|
|
||||||
nullable:$data["nullable"] ?? false,
|
|
||||||
required:$data["required"] ??false,
|
|
||||||
decimals:$data["decimals"] ?? 0,
|
|
||||||
collections:$data["collections"] ?? [],
|
|
||||||
min:$data["min"] ?? null,
|
|
||||||
max:$data["max"] ?? null,
|
|
||||||
default:$data["default"] ?? null,
|
|
||||||
optionsFrom:$data["optionsFrom"] ?? "" ,
|
|
||||||
optionsField:$data["optionsField"] ?? "" ,
|
|
||||||
optionsSuggest:$data["optionsSuggest"] ?? true,
|
|
||||||
unique:$data["unique"] ?? false,
|
|
||||||
layout:$data["layout"] ?? "" ,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @extends \Illuminate\Support\Collection<int|string, Field>
|
|
||||||
*/
|
|
||||||
final class FieldCollection extends Collection
|
|
||||||
{
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
Field ...$array
|
|
||||||
) {
|
|
||||||
parent::__construct($array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Schema[]
|
|
||||||
**/
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return collect($this)->values()->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function findByName(string $name): ?Field
|
|
||||||
{
|
|
||||||
return $this->firstWhere("name", $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromArray(array $data): FieldCollection
|
|
||||||
{
|
|
||||||
$items = array_map([Field::class, 'fromArray'], $data);
|
|
||||||
return new FieldCollection(...$items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromDB(string $data): FieldCollection
|
|
||||||
{
|
|
||||||
return FieldCollection::fromArray(\json_decode($data,true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Lucent\Channel\ChannelRepo;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Schema\Type as SchemaType;
|
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
use function Lucent\Svelte\svelte;
|
|
||||||
|
|
||||||
class FieldController extends Controller
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly FieldService $fieldService
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function new(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schemaName = $request->route("schemaName");
|
|
||||||
$collections = collect($channel->schemas)->where("type", SchemaType::COLLECTION)->values()->toArray();
|
|
||||||
$filesSchemas = collect($channel->schemas)->where("type", SchemaType::FILES)->values()->toArray();
|
|
||||||
|
|
||||||
$newField = new Field(
|
|
||||||
name: new FieldName(""),
|
|
||||||
label: "",
|
|
||||||
ui: "text"
|
|
||||||
);
|
|
||||||
|
|
||||||
return svelte(
|
|
||||||
layout: "channel",
|
|
||||||
view: "fieldNew",
|
|
||||||
title: "New field",
|
|
||||||
data: [
|
|
||||||
"schemas" => $channel->schemas,
|
|
||||||
"schema" => $channel->schemas->where("name", $schemaName)->first(),
|
|
||||||
"collections" => $collections,
|
|
||||||
"filesSchemas" => $filesSchemas,
|
|
||||||
"field" => $newField->toArray(),
|
|
||||||
"uiList" => UI::values(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->fieldService->create(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
data: $request->input("data")
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit(Request $request)
|
|
||||||
{
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schemaName = $request->route("schemaName");
|
|
||||||
$schema = $channel->schemas->where("name.value", $schemaName)->first();
|
|
||||||
$collections = collect($channel->schemas)->where("type", SchemaType::COLLECTION)->values()->toArray();
|
|
||||||
$filesSchemas = collect($channel->schemas)->where("type", SchemaType::FILES)->values()->toArray();
|
|
||||||
$field = collect($schema->fields)->where("name.value", $request->route("fid"))->first();
|
|
||||||
return svelte(
|
|
||||||
layout: "channel",
|
|
||||||
view: "fieldEdit",
|
|
||||||
title: "Edit field",
|
|
||||||
data: [
|
|
||||||
"schemas" => $channel->schemas,
|
|
||||||
"schema" => $schema,
|
|
||||||
"collections" => $collections,
|
|
||||||
"filesSchemas" => $filesSchemas,
|
|
||||||
"field" => $field,
|
|
||||||
"uiList" => UI::values(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function replace(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
$schema = $this->fieldService->replace(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
// fields:$request->input("fields")
|
|
||||||
fields: json_decode($request->input("fields"), true)
|
|
||||||
);
|
|
||||||
return ok($schema->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->fieldService->update(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
data: $request->input("data")
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function move(Request $request)
|
|
||||||
{
|
|
||||||
$newSchema = $this->fieldService->move(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
source: $request->input("source"),
|
|
||||||
target: $request->input("target") ?? "",
|
|
||||||
);
|
|
||||||
|
|
||||||
return ok($newSchema->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function trash(Request $request)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
$newSchema = $this->fieldService->trash(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
fieldName: $request->input("field"),
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok($newSchema->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restore(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$newSchema = $this->fieldService->restore(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
fieldName: $request->input("field"),
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok($newSchema->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$newSchema = $this->fieldService->delete(
|
|
||||||
schemaName: $request->route("schemaName"),
|
|
||||||
fieldName: $request->input("field"),
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok($newSchema->toArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
use JsonSerializable;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Validator\Validator;
|
|
||||||
|
|
||||||
|
|
||||||
class FieldName implements JsonSerializable
|
|
||||||
{
|
|
||||||
public string $value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
function __construct(string $value)
|
|
||||||
{
|
|
||||||
Validator::single("Name", $value, "min:2|max:50|alpha_dash");
|
|
||||||
$this->value = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function value(): string
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function equals(FieldName $name): bool
|
|
||||||
{
|
|
||||||
return $this->value === $name->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function jsonSerialize(): string
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
use Lucent\Channel\ChannelRepo;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Primitive\Collection;
|
|
||||||
use Lucent\Schema\Schema;
|
|
||||||
use Lucent\Schema\SchemaRepo;
|
|
||||||
|
|
||||||
readonly class FieldService
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private SchemaRepo $schemaRepo
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function create(
|
|
||||||
string $schemaName,
|
|
||||||
array $data
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
if (empty($data["name"]) || empty($data["label"])) {
|
|
||||||
throw new LucentException("Name and Label are required");
|
|
||||||
}
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name.value", $schemaName)->first();
|
|
||||||
$field = Field::fromArray($data);
|
|
||||||
$this->validateNameUnique($schema, $field->name);
|
|
||||||
$schema->fields->push($field);
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function update(
|
|
||||||
string $schemaName,
|
|
||||||
array $data
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
if (empty($data["name"]) || empty($data["label"])) {
|
|
||||||
throw new LucentException("Name and Label are required");
|
|
||||||
}
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name", $schemaName)->first();
|
|
||||||
$field = Field::fromArray($data);
|
|
||||||
if ($field->locked) {
|
|
||||||
throw new LucentException("Locked fields can't get updated");
|
|
||||||
}
|
|
||||||
$schema->fields = $schema->fields->map(function (Field $aField) use ($field) {
|
|
||||||
if (!$aField->name->equals($field->name)) {
|
|
||||||
return $aField;
|
|
||||||
}
|
|
||||||
return $field;
|
|
||||||
});
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function move(
|
|
||||||
string $schemaName,
|
|
||||||
string $source,
|
|
||||||
string $target,
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name", $schemaName)->first();
|
|
||||||
|
|
||||||
if ($source === $target) {
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sourceField = $schema->fields->where("name", $source)->first();
|
|
||||||
$fieldsWithoutSource = $schema->fields
|
|
||||||
->where("name", "!=", $source)
|
|
||||||
->values()
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
if (empty($target)) {
|
|
||||||
$schema->fields = new Collection([$sourceField, ...$fieldsWithoutSource]);
|
|
||||||
} else {
|
|
||||||
$newFields = collect($fieldsWithoutSource)->reduce(function ($carry, $afield) use ($sourceField, $target) {
|
|
||||||
$carry[] = $afield;
|
|
||||||
if ($afield->name->value === $target) {
|
|
||||||
$carry[] = $sourceField;
|
|
||||||
}
|
|
||||||
return $carry;
|
|
||||||
}, []);
|
|
||||||
$schema->fields = new Collection($newFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function trash(
|
|
||||||
string $schemaName,
|
|
||||||
string $fieldName,
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name.value", $schemaName)->first();
|
|
||||||
$field = $schema->fields->where("name", $fieldName)->first();
|
|
||||||
if ($field->trashed) {
|
|
||||||
throw new LucentException("Field is already in trash");
|
|
||||||
}
|
|
||||||
if ($field->locked) {
|
|
||||||
throw new LucentException("Locked fields can't get trashed");
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema->fields = $schema->fields->map(function (Field $aField) use ($fieldName) {
|
|
||||||
if ($aField->name->value !== $fieldName) {
|
|
||||||
return $aField;
|
|
||||||
}
|
|
||||||
$aField->trashed = true;
|
|
||||||
return $aField;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function restore(
|
|
||||||
string $schemaName,
|
|
||||||
string $fieldName,
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name.value", $schemaName)->first();
|
|
||||||
$field = $schema->fields->where("name", $fieldName)->first();
|
|
||||||
if (!$field->trashed) {
|
|
||||||
throw new LucentException("You can only restore trashed fields");
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema->fields = $schema->fields->map(function (Field $aField) use ($fieldName) {
|
|
||||||
if ($aField->name->value !== $fieldName) {
|
|
||||||
return $aField;
|
|
||||||
}
|
|
||||||
$aField->trashed = false;
|
|
||||||
return $aField;
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function delete(
|
|
||||||
string $schemaName,
|
|
||||||
string $fieldName,
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name.value", $schemaName)->first();
|
|
||||||
$field = $schema->fields->where("name", $fieldName)->first();
|
|
||||||
if (!$field->trashed) {
|
|
||||||
throw new LucentException("You can only delete trashed fields");
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema->fields = $schema->fields
|
|
||||||
->filter(fn(Field $aField) => $aField->name->value !== $fieldName)
|
|
||||||
->values();
|
|
||||||
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function replace(
|
|
||||||
string $schemaName,
|
|
||||||
array $fields
|
|
||||||
): Schema
|
|
||||||
{
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
$schema = $channel->schemas->where("name", $schemaName)->first();
|
|
||||||
$schema->fields = new Collection();
|
|
||||||
|
|
||||||
$newFields = collect($fields)->map(function ($fieldData) use ($schema) {
|
|
||||||
|
|
||||||
$field = Field::fromArray($fieldData);
|
|
||||||
$this->validateNameUnique($schema, $field->name);
|
|
||||||
return $field;
|
|
||||||
})->toArray();
|
|
||||||
$schema->fields = new Collection($newFields);
|
|
||||||
$this->schemaRepo->update($schema);
|
|
||||||
return $schema;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
private function validateNameUnique(Schema $schema, string $name): void
|
|
||||||
{
|
|
||||||
$fieldExists = collect($schema->fields)->where("name.value", $name)->first();
|
|
||||||
if (!empty($fieldExists)) {
|
|
||||||
throw new LucentException("Field with name $name exists in schema $schema->label");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Field;
|
|
||||||
|
|
||||||
use Lucent\Schema\FieldType;
|
|
||||||
|
|
||||||
readonly class UI
|
|
||||||
{
|
|
||||||
function __construct(
|
|
||||||
public string $name,
|
|
||||||
public string $label,
|
|
||||||
public FieldType $type,
|
|
||||||
public bool $regex,
|
|
||||||
public bool $mime,
|
|
||||||
public bool $required,
|
|
||||||
public bool $nullable,
|
|
||||||
public bool $decimals,
|
|
||||||
public bool $collections,
|
|
||||||
public bool $min,
|
|
||||||
public bool $max,
|
|
||||||
public bool $default,
|
|
||||||
public bool $locked,
|
|
||||||
public bool $readonly,
|
|
||||||
public bool $options,
|
|
||||||
public bool $layout,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getById(string $id): array
|
|
||||||
{
|
|
||||||
return self::buildUis()[$id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function values(): array
|
|
||||||
{
|
|
||||||
return array_values(self::buildUis());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function buildUis(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
"uuid" => new UI(
|
|
||||||
name: "uuid",
|
|
||||||
label: "UUID",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: false,
|
|
||||||
max: false,
|
|
||||||
default: false,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"text" => new UI(
|
|
||||||
name: "text",
|
|
||||||
label: "Text",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: true,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: true,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"textarea" => new UI(
|
|
||||||
name: "textarea",
|
|
||||||
label: "Textarea",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"color" => new UI(
|
|
||||||
name: "color",
|
|
||||||
label: "Color",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: false,
|
|
||||||
max: false,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: true,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"rich" => new UI(
|
|
||||||
name: "rich",
|
|
||||||
label: "Rich editor",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"block" => new UI(
|
|
||||||
name: "block",
|
|
||||||
label: "Block editor",
|
|
||||||
type: FieldType::JSON,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: true,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"file" => new UI(
|
|
||||||
name: "file",
|
|
||||||
label: "File",
|
|
||||||
type: FieldType::FILE,
|
|
||||||
regex: false,
|
|
||||||
mime: true,
|
|
||||||
required: false,
|
|
||||||
nullable: false,
|
|
||||||
decimals: false,
|
|
||||||
collections: true,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: false,
|
|
||||||
locked: false,
|
|
||||||
readonly: false, // feature for later
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"reference" => new UI(
|
|
||||||
name: "reference",
|
|
||||||
label: "Reference",
|
|
||||||
type: FieldType::REFERENCE,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: false,
|
|
||||||
nullable: false,
|
|
||||||
decimals: false,
|
|
||||||
collections: true,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: false,
|
|
||||||
locked: false,
|
|
||||||
readonly: false, // feature for later
|
|
||||||
options: false,
|
|
||||||
layout: true,
|
|
||||||
),
|
|
||||||
"checkbox" => new UI(
|
|
||||||
name: "checkbox",
|
|
||||||
label: "Checkbox",
|
|
||||||
type: FieldType::BOOLEAN,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: false,
|
|
||||||
max: false,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"number" => new UI(
|
|
||||||
name: "number",
|
|
||||||
label: "Number",
|
|
||||||
type: FieldType::NUMBER,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: true,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: true,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"date" => new UI(
|
|
||||||
name: "date",
|
|
||||||
label: "Date",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: true,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"datetime" => new UI(
|
|
||||||
name: "datetime",
|
|
||||||
label: "Datetime",
|
|
||||||
type: FieldType::STRING,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: true,
|
|
||||||
max: true,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: true,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"json" => new UI(
|
|
||||||
name: "json",
|
|
||||||
label: "JSON",
|
|
||||||
type: FieldType::JSON,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: true,
|
|
||||||
nullable: true,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: false,
|
|
||||||
max: false,
|
|
||||||
default: true,
|
|
||||||
locked: true,
|
|
||||||
readonly: true,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
"tab" => new UI(
|
|
||||||
name: "tab",
|
|
||||||
label: "Tab",
|
|
||||||
type: FieldType::TAB,
|
|
||||||
regex: false,
|
|
||||||
mime: false,
|
|
||||||
required: false,
|
|
||||||
nullable: false,
|
|
||||||
decimals: false,
|
|
||||||
collections: false,
|
|
||||||
min: false,
|
|
||||||
max: false,
|
|
||||||
default: false,
|
|
||||||
locked: true,
|
|
||||||
readonly: false,
|
|
||||||
options: false,
|
|
||||||
layout: false,
|
|
||||||
),
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,18 +3,27 @@
|
|||||||
namespace Lucent\File;
|
namespace Lucent\File;
|
||||||
|
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Record\File;
|
use Lucent\Record\File;
|
||||||
|
use Lucent\Record\QueryRecord;
|
||||||
use Lucent\Schema\Schema;
|
use Lucent\Schema\Schema;
|
||||||
use Lucent\Schema\Type;
|
use Lucent\Schema\Type;
|
||||||
|
|
||||||
class FileService
|
class FileService
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(
|
||||||
|
public ChannelService $channelService
|
||||||
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPath(QueryRecord $file): string
|
||||||
|
{
|
||||||
|
return $this->channelService->channel->url. "/storage/".$file->_file->path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws LucentException
|
* @throws LucentException
|
||||||
*/
|
*/
|
||||||
|
|||||||
+11
-9
@@ -102,7 +102,7 @@ function checkDuplicate(string $schemaName, string $checksum, int $filesize): st
|
|||||||
{
|
{
|
||||||
|
|
||||||
$record = DB::table("records")
|
$record = DB::table("records")
|
||||||
->where("_sys->schema", $schemaName)
|
->where("schema", $schemaName)
|
||||||
->where("_file->checksum", $checksum)
|
->where("_file->checksum", $checksum)
|
||||||
->where("_file->size", $filesize)
|
->where("_file->size", $filesize)
|
||||||
->first();
|
->first();
|
||||||
@@ -112,22 +112,24 @@ function checkDuplicate(string $schemaName, string $checksum, int $filesize): st
|
|||||||
|
|
||||||
function createThumbnail(Filesystem $disk, string $schemaPath, string $filename, UploadedFile $file): void
|
function createThumbnail(Filesystem $disk, string $schemaPath, string $filename, UploadedFile $file): void
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
$thumbDir = storage_path("app/public/thumbs/" . $schemaPath . "/");
|
||||||
|
if (!file_exists($thumbDir)) {
|
||||||
|
make_dir_r($thumbDir);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$image = ImageManagerStatic::make($file);
|
$image = ImageManagerStatic::make($file);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
logger($e->getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$image->fit(300, 300);
|
$image->fit(300, 300);
|
||||||
try {
|
try {
|
||||||
$image->encode('webp', 75);
|
$image->encode('webp', 75)->save($thumbDir .$filename);
|
||||||
|
|
||||||
$disk->put(
|
|
||||||
"thumbs/" . $schemaPath . "/" . $filename,
|
|
||||||
$image,
|
|
||||||
// 'public' // now managed by aws policy
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
logger($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Http\Controller\Api;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Lucent\Channel\ChannelContext;
|
|
||||||
use Lucent\Schema\FieldRepo;
|
|
||||||
use Lucent\Schema\SchemaRepo;
|
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
|
|
||||||
|
|
||||||
class FieldController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
public function create(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = SchemaRepo::findByName($request->input("schema"));
|
|
||||||
FieldRepo::create($schema, $request->input("field"));
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = SchemaRepo::findByName($request->input("schema"));
|
|
||||||
FieldRepo::update($schema, $request->input("field"));
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,12 +3,14 @@
|
|||||||
namespace Lucent\Http\Controller;
|
namespace Lucent\Http\Controller;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Contracts\Session\Session;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
use Lucent\Account\AccountService;
|
||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
use Lucent\Account\UserRepo;
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Svelte\Svelte;
|
use Lucent\Svelte\Svelte;
|
||||||
use function Lucent\Response\fail;
|
use function Lucent\Response\fail;
|
||||||
@@ -19,28 +21,27 @@ class AuthController extends Controller
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly AuthService $authService,
|
private readonly AuthService $authService,
|
||||||
|
private readonly AccountService $accountService,
|
||||||
|
private readonly ChannelService $channelService,
|
||||||
|
private readonly Session $session,
|
||||||
private readonly Svelte $svelte,
|
private readonly Svelte $svelte,
|
||||||
private readonly UserRepo $userRepo,
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function register(Request $request): View
|
public function register(Request $request): View|RedirectResponse
|
||||||
{
|
{
|
||||||
$userCount = $this->userRepo->count();
|
if ($this->accountService->countUsers() > 0) {
|
||||||
$email = $request->input("email");
|
return redirect($this->channelService->channel->lucentUrl . "/login");
|
||||||
$token = $request->input("token");
|
}
|
||||||
|
|
||||||
return svelte(
|
|
||||||
|
return $this->svelte->render(
|
||||||
layout: "account",
|
layout: "account",
|
||||||
view: "register",
|
view: "register",
|
||||||
title: "Create an account",
|
title: "Create an account",
|
||||||
data: [
|
|
||||||
'email' => $email,
|
|
||||||
'token' => $token,
|
|
||||||
'userCount' => $userCount
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,23 +49,15 @@ class AuthController extends Controller
|
|||||||
public function postRegister(Request $request): Response
|
public function postRegister(Request $request): Response
|
||||||
{
|
{
|
||||||
|
|
||||||
try {
|
if ($this->accountService->countUsers() > 0) {
|
||||||
if ($request->input("isAdmin")) {
|
abort(400);
|
||||||
$this->authService->registerAdmin(
|
|
||||||
name: $request->input("name"),
|
|
||||||
password: $request->input("password"),
|
|
||||||
email: $request->input("email"),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->authService->register(
|
|
||||||
name: $request->input("name"),
|
|
||||||
password: $request->input("password"),
|
|
||||||
email: $request->input("email"),
|
|
||||||
token: $request->input("token") ?? "",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->authService->registerAdmin(
|
||||||
|
name: $request->input("name"),
|
||||||
|
email: $request->input("email"),
|
||||||
|
);
|
||||||
} catch (LucentException $th) {
|
} catch (LucentException $th) {
|
||||||
return fail($th);
|
return fail($th);
|
||||||
}
|
}
|
||||||
@@ -72,8 +65,12 @@ class AuthController extends Controller
|
|||||||
return ok();
|
return ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(): View
|
public function login(): View|RedirectResponse
|
||||||
{
|
{
|
||||||
|
if ($this->accountService->countUsers() == 0) {
|
||||||
|
return redirect($this->channelService->channel->lucentUrl . "/register");
|
||||||
|
}
|
||||||
|
|
||||||
return $this->svelte->render(
|
return $this->svelte->render(
|
||||||
layout: "account",
|
layout: "account",
|
||||||
view: "login",
|
view: "login",
|
||||||
@@ -118,8 +115,8 @@ class AuthController extends Controller
|
|||||||
|
|
||||||
public function logout(): RedirectResponse
|
public function logout(): RedirectResponse
|
||||||
{
|
{
|
||||||
session()->flush();
|
$this->session->flush();
|
||||||
return redirect("/login");
|
return redirect($this->channelService->channel->lucentUrl . "/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Lucent\Account\Auth;
|
|
||||||
use Lucent\Channel\ChannelContext;
|
|
||||||
use Lucent\Query\Options;
|
|
||||||
use Lucent\Query\Reference;
|
|
||||||
|
|
||||||
class EdgeController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -121,9 +121,9 @@ class FileController extends Controller
|
|||||||
})->toArray();
|
})->toArray();
|
||||||
|
|
||||||
|
|
||||||
$queryResult = $this->query
|
$graph = $this->query
|
||||||
->filter([
|
->filter([
|
||||||
"_sys.schema" => $schema->name
|
"schema" => $schema->name
|
||||||
])
|
])
|
||||||
->limit(15)
|
->limit(15)
|
||||||
->skip(0)
|
->skip(0)
|
||||||
@@ -132,7 +132,6 @@ class FileController extends Controller
|
|||||||
->parentsDepth(0)
|
->parentsDepth(0)
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
$graph = $queryResult->getQueryRecords();
|
|
||||||
return ok($graph->records->toArray());
|
return ok($graph->records->toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Lucent\Schema\FolderRepo;
|
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
|
|
||||||
class FolderController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
public function create(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$folder = FolderRepo::create($request->input("name"));
|
|
||||||
} catch (\Lucent\LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok((array)$folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request, string $cid)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$folder = FolderRepo::update(
|
|
||||||
id: $request->input("id"),
|
|
||||||
name: $request->input("name"),
|
|
||||||
);
|
|
||||||
} catch (\Lucent\LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
return ok((array)$folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request, string $cid, string $folderid)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
FolderRepo::delete($folderid);
|
|
||||||
} catch (\Lucent\LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return redirect()->back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,6 @@ use function Lucent\Response\ok;
|
|||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ChannelService $channelService,
|
|
||||||
private readonly Svelte $svelte,
|
private readonly Svelte $svelte,
|
||||||
private readonly UserRepo $userRepo,
|
private readonly UserRepo $userRepo,
|
||||||
private readonly Query $query,
|
private readonly Query $query,
|
||||||
@@ -45,7 +44,7 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
$limit = 30;
|
$limit = 30;
|
||||||
|
|
||||||
$queryResult = $this->query
|
$graph = $this->query
|
||||||
->filter($arguments)
|
->filter($arguments)
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->childrenDepth(1)
|
->childrenDepth(1)
|
||||||
@@ -53,15 +52,12 @@ class HomeController extends Controller
|
|||||||
->sort($sort)
|
->sort($sort)
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
|
|
||||||
$graph = $queryResult->getQueryRecords();
|
|
||||||
|
|
||||||
$users = $this->userRepo->all();
|
$users = $this->userRepo->all();
|
||||||
|
|
||||||
return ok([
|
return ok([
|
||||||
"users" => $users,
|
"users" => $users,
|
||||||
"records" => $graph->getRootRecords()->toArray(),
|
"records" => $graph->getRootRecords()->toArray(),
|
||||||
"graph" => $graph->toArray(),
|
"graph" => toArray($graph),
|
||||||
"modalUrl" => $request->fullUrl(),
|
"modalUrl" => $request->fullUrl(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ use Lucent\Account\AccountService;
|
|||||||
use Lucent\Account\AuthService;
|
use Lucent\Account\AuthService;
|
||||||
use Lucent\Account\UserRepo;
|
use Lucent\Account\UserRepo;
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\Field\System;
|
|
||||||
use Lucent\LucentException;
|
use Lucent\LucentException;
|
||||||
use Lucent\Query\Operator;
|
use Lucent\Query\Operator;
|
||||||
use Lucent\Query\Query;
|
use Lucent\Query\Query;
|
||||||
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\Schema\System;
|
||||||
use Lucent\Schema\Validator\ValidatorException;
|
use Lucent\Schema\Validator\ValidatorException;
|
||||||
use Lucent\Svelte\Svelte;
|
use Lucent\Svelte\Svelte;
|
||||||
use function Lucent\Response\fail;
|
use function Lucent\Response\fail;
|
||||||
@@ -39,13 +39,13 @@ class RecordController extends Controller
|
|||||||
{
|
{
|
||||||
$schemaName = $request->route("schemaName");
|
$schemaName = $request->route("schemaName");
|
||||||
$users = $this->accountService->all();
|
$users = $this->accountService->all();
|
||||||
$schema = $this->channelService->channel->schemas->where("name", $schemaName)->first();
|
$schema = $this->channelService->getSchema($schemaName)->get();
|
||||||
$urlParams = $request->all();
|
$urlParams = $request->all();
|
||||||
$sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
|
$sort = data_get($urlParams, "sort") ?? "-_sys.updatedAt";
|
||||||
$filter = data_get($urlParams, "filter") ?? [];
|
$filter = data_get($urlParams, "filter") ?? [];
|
||||||
$arguments = array_merge([
|
$arguments = array_merge([
|
||||||
"_sys.schema" => $schema->name,
|
"schema" => $schema->name,
|
||||||
"_sys.status_in" => "draft,published",
|
"status_in" => "draft,published",
|
||||||
], $filter);
|
], $filter);
|
||||||
|
|
||||||
|
|
||||||
@@ -53,38 +53,32 @@ class RecordController extends Controller
|
|||||||
$limit = 15;
|
$limit = 15;
|
||||||
$records = [];
|
$records = [];
|
||||||
$graphArray = null;
|
$graphArray = null;
|
||||||
$total = 0;
|
|
||||||
|
|
||||||
try {
|
$graph = $this->query
|
||||||
$queryResult = $this->query
|
|
||||||
->filter($arguments)
|
->filter($arguments)
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->status(explode(",", $arguments["_sys.status_in"]))
|
->status(explode(",", $arguments["status_in"]))
|
||||||
->skip($skip)
|
->skip($skip)
|
||||||
->sort($sort)
|
->sort($sort)
|
||||||
->childrenDepth(1)
|
->childrenDepth(1)
|
||||||
->parentsDepth(0)
|
->parentsDepth(0)
|
||||||
->runWithCount();
|
->runWithCount();
|
||||||
|
|
||||||
$graph = $queryResult->getQueryRecords();
|
|
||||||
$graphArray = $graph->toArray();
|
|
||||||
$total = $queryResult->getTotal();
|
|
||||||
$records = $graph->getRootRecords()->toArray();
|
$records = $graph->getRootRecords()->toArray();
|
||||||
} catch (SubqueryNoResultException) {
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
"schemas" => $this->channelService->channel->schemas,
|
"schemas" => $this->channelService->channel->schemas,
|
||||||
"schema" => $schema,
|
"schema" => $schema,
|
||||||
"users" => $users,
|
"users" => $users,
|
||||||
"records" => $records,
|
"records" => $records,
|
||||||
"graph" => $graphArray,
|
"graph" => toArray($graph),
|
||||||
"systemFields" => array_values(System::list()),
|
"systemFields" => array_values(System::list()),
|
||||||
"operators" => array_values(Operator::list()),
|
"operators" => array_values(Operator::list()),
|
||||||
"sort" => $sort,
|
"sort" => $sort,
|
||||||
"limit" => $limit,
|
"limit" => $limit,
|
||||||
"skip" => $skip,
|
"skip" => $skip,
|
||||||
"total" => $total,
|
"total" => $graph->total ?? 0,
|
||||||
"filter" => $request->input("filter") ?? [],
|
"filter" => $request->input("filter") ?? [],
|
||||||
"inModal" => true,
|
"inModal" => true,
|
||||||
];
|
];
|
||||||
@@ -192,7 +186,7 @@ class RecordController extends Controller
|
|||||||
$rid = $request->route("rid");
|
$rid = $request->route("rid");
|
||||||
|
|
||||||
|
|
||||||
$queryResult = $this->query
|
$graph = $this->query
|
||||||
->filter(["id" => $rid])
|
->filter(["id" => $rid])
|
||||||
->limit(1)
|
->limit(1)
|
||||||
->skip(0)
|
->skip(0)
|
||||||
@@ -203,9 +197,7 @@ class RecordController extends Controller
|
|||||||
->run();
|
->run();
|
||||||
|
|
||||||
|
|
||||||
$graph = $queryResult->getQueryRecords();
|
if ($graph->records->isEmpty()) {
|
||||||
|
|
||||||
if (empty($graph->records[0])) {
|
|
||||||
return $this->svelte->render(
|
return $this->svelte->render(
|
||||||
layout: "channel",
|
layout: "channel",
|
||||||
view: "recordNotFound",
|
view: "recordNotFound",
|
||||||
@@ -213,8 +205,8 @@ class RecordController extends Controller
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$record = $graph->records[0];
|
$record = $graph->records->first();
|
||||||
$schema = $this->channelService->channel->schemas->where("name", $record->_sys->schema)->first();
|
$schema = $this->channelService->getSchema($record->schema)->get();
|
||||||
$recordHistory = $this->recordManager->fromSession($request->session())->push($rid)->getRecords($rid);
|
$recordHistory = $this->recordManager->fromSession($request->session())->push($rid)->getRecords($rid);
|
||||||
$users = $this->userRepo->all();
|
$users = $this->userRepo->all();
|
||||||
return $this->svelte->render(
|
return $this->svelte->render(
|
||||||
@@ -223,11 +215,10 @@ class RecordController extends Controller
|
|||||||
title: "Edit Record",
|
title: "Edit Record",
|
||||||
data: [
|
data: [
|
||||||
"schema" => $schema,
|
"schema" => $schema,
|
||||||
"graph" => $graph->toArray(),
|
"graph" => toArray($graph),
|
||||||
"record" => $record->toArray(),
|
"record" => toArray($record),
|
||||||
"users" => $users,
|
"users" => $users,
|
||||||
"recordHistory" => $recordHistory,
|
"recordHistory" => $recordHistory,
|
||||||
"isCreateMode" => $record->_sys->status === "empty",
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -294,37 +285,37 @@ class RecordController extends Controller
|
|||||||
|
|
||||||
if ($request->input("isCreateMode")) {
|
if ($request->input("isCreateMode")) {
|
||||||
$this->recordService->create(
|
$this->recordService->create(
|
||||||
schemaName: $request->input("record._sys.schema"),
|
schemaName: $request->input("record.schema"),
|
||||||
data: $request->input("record.data"),
|
data: $request->input("record.data"),
|
||||||
id: $request->input("record.id"),
|
id: $request->input("record.id"),
|
||||||
file: $request->input("record._file") ?? [],
|
file: $request->input("record._file") ?? [],
|
||||||
edges: $request->input("edges"),
|
edges: $request->input("edges"),
|
||||||
status: $request->input("record._sys.status"),
|
status: $request->input("record.status"),
|
||||||
uploadFromUrl: ""
|
uploadFromUrl: ""
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->recordService->update(
|
$this->recordService->update(
|
||||||
id: $request->input("record.id"),
|
id: $request->input("record.id"),
|
||||||
data: $request->input("record.data"),
|
data: $request->input("record.data"),
|
||||||
status: $request->input("record._sys.status"),
|
status: $request->input("record.status"),
|
||||||
edges: $request->input("edges"),
|
edges: $request->input("edges"),
|
||||||
updateEdges: true,
|
updateEdges: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$queryResult = $this->query
|
$newGraph = $this->query
|
||||||
->filter(["id" => $request->input("record.id")])
|
->filter(["id" => $request->input("record.id")])
|
||||||
->limit(10)
|
->limit(10)
|
||||||
->childrenDepth(2)
|
->childrenDepth(2)
|
||||||
->parentsDepth(1)
|
->parentsDepth(1)
|
||||||
->run();
|
->run();
|
||||||
$newGraph = $queryResult->getQueryRecords();
|
|
||||||
} catch (ValidatorException $th) {
|
} catch (ValidatorException $th) {
|
||||||
return fail($th->getValidatorErrors());
|
return fail($th->getValidatorErrors());
|
||||||
} catch (LucentException $th) {
|
} catch (LucentException $th) {
|
||||||
return fail($th);
|
return fail($th);
|
||||||
}
|
}
|
||||||
return ok($newGraph->toArray());
|
return ok(toArray($newGraph));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Contracts\View\View;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Response;
|
|
||||||
use Lucent\Channel\ChannelRepo;
|
|
||||||
use Lucent\LucentException;
|
|
||||||
use Lucent\Schema\SchemaRepo;
|
|
||||||
use Lucent\Schema\SchemaService;
|
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
use function Lucent\Svelte\svelte;
|
|
||||||
|
|
||||||
class SchemaController extends Controller
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly SchemaRepo $schemaRepo,
|
|
||||||
private readonly SchemaService $schemaService
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public function new(): View
|
|
||||||
{
|
|
||||||
$schemas = $this->schemaRepo->all();
|
|
||||||
|
|
||||||
return svelte(
|
|
||||||
layout: "channel",
|
|
||||||
view: "schemaNew",
|
|
||||||
title: "Create schema",
|
|
||||||
data: [
|
|
||||||
"schemas" => $schemas,
|
|
||||||
"schema" => Schema::fromArray([]),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create(Request $request): Response
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->schemaService->create(
|
|
||||||
name: $request->input("name"),
|
|
||||||
label: $request->input("label"),
|
|
||||||
type: $request->input("type"),
|
|
||||||
isEntry: $request->input("isEntry"),
|
|
||||||
revisionRetentionDays: $request->input("revisionRetentionDays"),
|
|
||||||
revisionRetentionNumber: $request->input("revisionRetentionNumber"),
|
|
||||||
trashedRetentionDays: $request->input("trashedRetentionDays"),
|
|
||||||
fields: [],
|
|
||||||
path: $request->input("path"),
|
|
||||||
);
|
|
||||||
} catch (LucentException $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function edit(string $name): View
|
|
||||||
{
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
return svelte(
|
|
||||||
layout: "channel",
|
|
||||||
view: "schemaEdit",
|
|
||||||
title: "Schemas",
|
|
||||||
data: [
|
|
||||||
"schemas" => $channel->schemas,
|
|
||||||
"schema" => $channel->schemas->where("name.value", $name)->first(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request): View
|
|
||||||
{
|
|
||||||
$channel = ChannelRepo::current();
|
|
||||||
return svelte(
|
|
||||||
layout: "channel",
|
|
||||||
view: "schemaDelete",
|
|
||||||
title: "Schemas",
|
|
||||||
data: [
|
|
||||||
"channel" => $channel,
|
|
||||||
"schemas" => $channel->schemas,
|
|
||||||
"schema" => $channel->schemas->firstWhere("name", $request->route("name")),
|
|
||||||
"nav" => "collections",
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request): Response
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = $this->schemaService->update(
|
|
||||||
name: $request->input("name"),
|
|
||||||
label: $request->input("label"),
|
|
||||||
isEntry: $request->input("isEntry"),
|
|
||||||
color: $request->input("color") ?? "",
|
|
||||||
visible: $request->input("visible") ?? [],
|
|
||||||
titleTemplate: $request->input("titleTemplate") ?? "",
|
|
||||||
revisionRetentionDays: $request->input("revisionRetentionDays"),
|
|
||||||
revisionRetentionNumber: $request->input("revisionRetentionNumber"),
|
|
||||||
trashedRetentionDays: $request->input("trashedRetentionDays"),
|
|
||||||
path: $request->input("path"),
|
|
||||||
);
|
|
||||||
} catch (LucentException $e) {
|
|
||||||
return fail($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok($schema->toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function postDelete(Request $request): Response
|
|
||||||
{
|
|
||||||
|
|
||||||
$this->schemaService->delete($request->input("name"));
|
|
||||||
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Http\Controller;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Lucent\Account\Auth;
|
|
||||||
use Lucent\Channel\ChannelContext;
|
|
||||||
use Lucent\Schema\SchemaRepo;
|
|
||||||
use Lucent\View\ViewRepo;
|
|
||||||
use function Lucent\Response\fail;
|
|
||||||
use function Lucent\Response\ok;
|
|
||||||
|
|
||||||
class ViewController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
public function redirect(Request $request, string $cid, string $schemaName, string $viewName)
|
|
||||||
{
|
|
||||||
|
|
||||||
$schema = SchemaRepo::findByName($schemaName);
|
|
||||||
$view = $schema->views->whereName($viewName);
|
|
||||||
parse_str($view->params, $viewParamsArray);
|
|
||||||
return \redirect("/c/{$cid}/content/{$schemaName}/views/{$viewName}?{$view->params}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function create(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = SchemaRepo::findByName($request->input("schemaName"));
|
|
||||||
ViewRepo::create($schema, $request->input("view"), Auth::currentUserId());
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function update(Request $request)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = SchemaRepo::findByName($request->input("schemaName"));
|
|
||||||
ViewRepo::update($schema, $request->input("view"));
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
$schema = SchemaRepo::findByName($request->input("schemaName"));
|
|
||||||
$view = $schema->views->whereName($request->input("view.name"));
|
|
||||||
|
|
||||||
return ok((array)$view);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(Request $request, string $cid, string $schemaName, string $viewName)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$schema = SchemaRepo::findByName($schemaName);
|
|
||||||
ViewRepo::delete($schema, $viewName);
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return fail($th);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect("c/{$cid}/content/{$schemaName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,12 +6,6 @@ use Lucent\Http\Controller\Api\FileController;
|
|||||||
use Lucent\Http\Controller\Api\RecordController;
|
use Lucent\Http\Controller\Api\RecordController;
|
||||||
use Lucent\Http\Controller\Api\SchemaController;
|
use Lucent\Http\Controller\Api\SchemaController;
|
||||||
|
|
||||||
Route::middleware('auth.api:developer')->group(function () {
|
|
||||||
Route::post('/schemas', [SchemaController::class, 'create']);
|
|
||||||
Route::put('/schemas/', [SchemaController::class, 'update']);
|
|
||||||
Route::delete('/schemas/{name}', [SchemaController::class, 'delete']);
|
|
||||||
Route::post('/schemas/fields', [SchemaController::class, 'fields']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware('auth.api:editor')->group(function () {
|
Route::middleware('auth.api:editor')->group(function () {
|
||||||
|
|
||||||
@@ -29,26 +23,3 @@ Route::middleware('auth.api:reader')->group(function () {
|
|||||||
Route::get('/records', [RecordController::class, 'records']);
|
Route::get('/records', [RecordController::class, 'records']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// They need testing
|
|
||||||
// Route::middleware('auth.api')->prefix("/fields")->controller(FieldController::class)->group(function () {
|
|
||||||
// Route::post('/', 'create');
|
|
||||||
// Route::put('/', 'update');
|
|
||||||
// Route::delete('/{id}', 'delete');
|
|
||||||
// });
|
|
||||||
|
|
||||||
//Route::middleware(["auth.api"])->group(function () {
|
|
||||||
//
|
|
||||||
//// Route::get('/{rid}', 'findOne');
|
|
||||||
//
|
|
||||||
//// Route::delete('/records/{id}', [RecordController::class, 'delete']);
|
|
||||||
//// Route::post('/bulk', 'bulkCreate');
|
|
||||||
//// Route::put('/bulk', 'bulkUpdate');
|
|
||||||
//// Route::delete('/bulk', 'bulkDelete');
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//});
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//Route::middleware('auth.api')->prefix("/files")->controller(FileController::class)->group(function () {
|
|
||||||
// Route::post('/', 'upload');
|
|
||||||
//});
|
|
||||||
|
|||||||
@@ -41,16 +41,6 @@ Route::group([
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/schemas/")->group(function () {
|
|
||||||
Route::get('/new/', [SchemaController::class, 'new']);
|
|
||||||
Route::post('/', [SchemaController::class, 'create']);
|
|
||||||
Route::get('/{name}/edit', [SchemaController::class, 'edit']);
|
|
||||||
Route::put('/', [SchemaController::class, 'update']);
|
|
||||||
Route::get('/{name}/delete', [SchemaController::class, 'delete']);
|
|
||||||
Route::post('/delete', [SchemaController::class, 'postDelete']);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Route::middleware(["lucent.auth"])->prefix("/records")->group(function () {
|
Route::middleware(["lucent.auth"])->prefix("/records")->group(function () {
|
||||||
|
|
||||||
Route::get('/new', [RecordController::class, 'new']);
|
Route::get('/new', [RecordController::class, 'new']);
|
||||||
@@ -88,9 +78,6 @@ Route::group([
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Route::get('/fs/cache/{path}', [FileController::class, 'get'])->where('path', '.*');
|
|
||||||
Route::get('/fs/{path}', [FileController::class, 'get'])->where('path', '.*');
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ namespace Lucent;
|
|||||||
use Illuminate\Routing\Router;
|
use Illuminate\Routing\Router;
|
||||||
use Illuminate\Support\Facades\View;
|
use Illuminate\Support\Facades\View;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Intervention\Image\ImageManager;
|
||||||
use Lucent\Channel\ChannelService;
|
use Lucent\Channel\ChannelService;
|
||||||
use Lucent\Commands\CompileConfig;
|
use Lucent\Commands\CompileConfig;
|
||||||
use Lucent\Commands\RebuildThumbnails;
|
use Lucent\Commands\RebuildThumbnails;
|
||||||
|
use Lucent\File\FileService;
|
||||||
use Lucent\File\ImageService;
|
use Lucent\File\ImageService;
|
||||||
|
|
||||||
class LucentServiceProvider extends ServiceProvider
|
class LucentServiceProvider extends ServiceProvider
|
||||||
@@ -21,6 +23,11 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
return ChannelService::fromConfig();
|
return ChannelService::fromConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->app->bind(ImageManager::class, function () {
|
||||||
|
return new ImageManager(['driver' => 'imagick']);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,6 +43,7 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
$this->loadRoutesFrom(__DIR__ . '/Http/web.php');
|
$this->loadRoutesFrom(__DIR__ . '/Http/web.php');
|
||||||
$this->loadRoutesFrom(__DIR__ . '/Http/api.php');
|
$this->loadRoutesFrom(__DIR__ . '/Http/api.php');
|
||||||
|
|
||||||
|
$this->loadMigrationsFrom(__DIR__ . '/Database/migrations');
|
||||||
|
|
||||||
if ($this->app->runningInConsole()) {
|
if ($this->app->runningInConsole()) {
|
||||||
$this->commands([
|
$this->commands([
|
||||||
@@ -45,6 +53,7 @@ class LucentServiceProvider extends ServiceProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
View::share('image', app()->make(ImageService::class));
|
View::share('image', app()->make(ImageService::class));
|
||||||
|
View::share('file', app()->make(FileService::class));
|
||||||
|
|
||||||
$this->publishes([
|
$this->publishes([
|
||||||
__DIR__ . '/Config/main.php' => config_path('lucent.php'),
|
__DIR__ . '/Config/main.php' => config_path('lucent.php'),
|
||||||
|
|||||||
+5
-9
@@ -58,7 +58,7 @@ final class Query
|
|||||||
if (!empty($edgesIds)) {
|
if (!empty($edgesIds)) {
|
||||||
$edgeRecords = DB::table('records')
|
$edgeRecords = DB::table('records')
|
||||||
->whereIn("id", $edgesIds)
|
->whereIn("id", $edgesIds)
|
||||||
->whereIn("_sys->status", $this->options->status)
|
->whereIn("status", $this->options->status)
|
||||||
->get()->toArray();
|
->get()->toArray();
|
||||||
}
|
}
|
||||||
$resultsRecordsUnique = collect(array_merge($resultsRecords, $edgeRecords))->unique("id")->values()->toArray();
|
$resultsRecordsUnique = collect(array_merge($resultsRecords, $edgeRecords))->unique("id")->values()->toArray();
|
||||||
@@ -76,7 +76,7 @@ final class Query
|
|||||||
$queryRecords = collect($records)->map(function ($recordData) {
|
$queryRecords = collect($records)->map(function ($recordData) {
|
||||||
|
|
||||||
$record = Record::fromDB($recordData);
|
$record = Record::fromDB($recordData);
|
||||||
$record->data = $this->inputFormatter->fill($record->_sys->schema, $record->data);
|
$record->data = $this->inputFormatter->fill($record->schema, $record->data);
|
||||||
$queryRecord = QueryRecord::fromRecord($record);
|
$queryRecord = QueryRecord::fromRecord($record);
|
||||||
$queryRecord->isRoot = data_get($recordData, "isRoot") === true;
|
$queryRecord->isRoot = data_get($recordData, "isRoot") === true;
|
||||||
return $queryRecord;
|
return $queryRecord;
|
||||||
@@ -103,9 +103,7 @@ final class Query
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws SubqueryNoResultException
|
|
||||||
*/
|
|
||||||
private function parseFilters(Builder $query): Builder
|
private function parseFilters(Builder $query): Builder
|
||||||
{
|
{
|
||||||
$filters = $this->filter->run(new Query($this->channelService, $this->inputFormatter));
|
$filters = $this->filter->run(new Query($this->channelService, $this->inputFormatter));
|
||||||
@@ -148,7 +146,7 @@ final class Query
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$query->whereIn("_sys->status", $this->options->status);
|
$query->whereIn("status", $this->options->status);
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,9 +209,7 @@ final class Query
|
|||||||
->get()->toArray();
|
->get()->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws SubqueryNoResultException
|
|
||||||
*/
|
|
||||||
public
|
public
|
||||||
function runWithCount(): Graph
|
function runWithCount(): Graph
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
namespace Lucent\Record;
|
namespace Lucent\Record;
|
||||||
|
|
||||||
use Illuminate\Contracts\Session\Session;
|
use Illuminate\Contracts\Session\Session;
|
||||||
use Lucent\Primitive\Collection;
|
|
||||||
use Lucent\Query\Query;
|
use Lucent\Query\Query;
|
||||||
use Lucent\Schema\Schema;
|
|
||||||
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
@@ -79,19 +77,16 @@ class Manager
|
|||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Collection<Schema> $schemas
|
|
||||||
*/
|
|
||||||
public function getRecords(?string $ignoreId = null): array
|
public function getRecords(?string $ignoreId = null): array
|
||||||
{
|
{
|
||||||
|
|
||||||
$queryResult = $this->query
|
$graph = $this->query
|
||||||
->filter(["id_in" => $this->getIdsExcept($ignoreId)])
|
->filter(["id_in" => $this->getIdsExcept($ignoreId)])
|
||||||
->limit(7)
|
->limit(7)
|
||||||
->run();
|
->run();
|
||||||
|
|
||||||
|
|
||||||
$graph = $queryResult->getQueryRecords();
|
|
||||||
|
|
||||||
return $this->order($graph->records->toArray());
|
return $this->order($graph->records->toArray());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ class QueryRecord
|
|||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
|
public string $schema,
|
||||||
|
public Status $status,
|
||||||
public System $_sys,
|
public System $_sys,
|
||||||
public RecordData $data,
|
public RecordData $data,
|
||||||
public bool $isRoot,
|
public bool $isRoot,
|
||||||
@@ -18,33 +20,12 @@ class QueryRecord
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return json_decode(json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws LucentException
|
|
||||||
*/
|
|
||||||
public static function fromArray(array $data): QueryRecord
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
return new QueryRecord(
|
|
||||||
id: $data["id"],
|
|
||||||
_sys: System::fromArray($data["_sys"]),
|
|
||||||
data: new RecordData($data["data"]),
|
|
||||||
isRoot: $data["isRoot"] ?? false,
|
|
||||||
_file: $data["_file"] ? new File(...$data["_file"]) : null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromRecord(Record $record): QueryRecord
|
public static function fromRecord(Record $record): QueryRecord
|
||||||
{
|
{
|
||||||
return new QueryRecord(
|
return new QueryRecord(
|
||||||
id: $record->id,
|
id: $record->id,
|
||||||
|
schema: $record->schema,
|
||||||
|
status: $record->status,
|
||||||
_sys: $record->_sys,
|
_sys: $record->_sys,
|
||||||
data: $record->data,
|
data: $record->data,
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
|
|||||||
+6
-18
@@ -11,6 +11,8 @@ class Record implements JsonSerializable
|
|||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
|
public string $schema,
|
||||||
|
public Status $status,
|
||||||
public System $_sys,
|
public System $_sys,
|
||||||
public RecordData $data,
|
public RecordData $data,
|
||||||
public ?File $_file = null,
|
public ?File $_file = null,
|
||||||
@@ -18,15 +20,13 @@ class Record implements JsonSerializable
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toDB(): array
|
public function toDB(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"id" => $this->id,
|
"id" => $this->id,
|
||||||
|
"status" => $this->status->value,
|
||||||
|
"schema" => $this->schema,
|
||||||
"_sys" => json_encode($this->_sys),
|
"_sys" => json_encode($this->_sys),
|
||||||
"_file" => json_encode($this->_file),
|
"_file" => json_encode($this->_file),
|
||||||
"data" => json_encode($this->data),
|
"data" => json_encode($this->data),
|
||||||
@@ -46,6 +46,8 @@ class Record implements JsonSerializable
|
|||||||
|
|
||||||
return new Record(
|
return new Record(
|
||||||
id: $data->id,
|
id: $data->id,
|
||||||
|
schema: $data->schema,
|
||||||
|
status: Status::from($data->status),
|
||||||
_sys: System::fromArray(json_decode($data->_sys, true)),
|
_sys: System::fromArray(json_decode($data->_sys, true)),
|
||||||
data: new RecordData(json_decode($data->data, true)),
|
data: new RecordData(json_decode($data->data, true)),
|
||||||
_file: $file,
|
_file: $file,
|
||||||
@@ -58,20 +60,6 @@ class Record implements JsonSerializable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromArray(array $data): Record
|
|
||||||
{
|
|
||||||
|
|
||||||
$file = null;
|
|
||||||
if (!empty($data["_file"])) {
|
|
||||||
$file = File::fromArray($data["_file"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Record(
|
|
||||||
id: $data["id"],
|
|
||||||
_sys: System::fromArray($data["_sys"]),
|
|
||||||
data: new RecordData($data["data"]),
|
|
||||||
_file: $file,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Record;
|
|
||||||
|
|
||||||
use Lucent\Edge\QueryEdge;
|
|
||||||
|
|
||||||
class RecordGraph
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param \Lucent\Edge\QueryEdge[] $edges
|
|
||||||
* @param \Lucent\Record\EdgeRecord[] $nodes
|
|
||||||
*/
|
|
||||||
function __construct(
|
|
||||||
public readonly array $edges,
|
|
||||||
public readonly array $nodes,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromArray(array $data): RecordGraph
|
|
||||||
{
|
|
||||||
return new RecordGraph(
|
|
||||||
edges: collect($data["edges"] ?? [])->map(fn ($edge) => new QueryEdge(...$edge))->toArray(),
|
|
||||||
nodes: collect($data["nodes"] ?? [])->map(fn ($node) => EdgeRecord::fromArray($node))->toArray(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,10 +18,10 @@ class RecordRepo
|
|||||||
/**
|
/**
|
||||||
* @param array<string> $ids
|
* @param array<string> $ids
|
||||||
*/
|
*/
|
||||||
public static function updateStatusBulk(RecordStatus $status, array $ids): void
|
public static function updateStatusBulk(Status $status, array $ids): void
|
||||||
{
|
{
|
||||||
DB::table("records")->whereIn("id", $ids)->update([
|
DB::table("records")->whereIn("id", $ids)->update([
|
||||||
'_sys->status' => $status->value()
|
'status' => $status->value
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,11 +60,9 @@ readonly class RecordService
|
|||||||
$uploadResult = FileService::create($schema, $uploadFromUrl, $file);
|
$uploadResult = FileService::create($schema, $uploadFromUrl, $file);
|
||||||
|
|
||||||
$uniqueEdges = collect($edges)
|
$uniqueEdges = collect($edges)
|
||||||
->map(fn($e) => (array)(new Edge(...$e)))
|
|
||||||
->map(function ($edge, $index) {
|
->map(function ($edge, $index) {
|
||||||
$edgeData = (array)(new Edge(...$edge));
|
$edge["rank"] = $index;
|
||||||
$edgeData["rank"] = $index;
|
return (array)(new Edge(...$edge));
|
||||||
return $edgeData;
|
|
||||||
})
|
})
|
||||||
->unique(fn($e) => $e['field'] . $e['source'] . $e['target'] . $e['sourceSchema'])
|
->unique(fn($e) => $e['field'] . $e['source'] . $e['target'] . $e['sourceSchema'])
|
||||||
->values()->toArray();
|
->values()->toArray();
|
||||||
@@ -77,7 +75,9 @@ readonly class RecordService
|
|||||||
|
|
||||||
$record = new Record(
|
$record = new Record(
|
||||||
id: $id ?? Id::new(),
|
id: $id ?? Id::new(),
|
||||||
_sys: System::newRecord($schema, $this->authService->currentUserId(), $status),
|
schema: $schema->name,
|
||||||
|
status: Status::from($status),
|
||||||
|
_sys: System::newRecord($this->authService->currentUserId()),
|
||||||
data: $formattedData,
|
data: $formattedData,
|
||||||
_file: $uploadResult->recordFile,
|
_file: $uploadResult->recordFile,
|
||||||
);
|
);
|
||||||
@@ -109,33 +109,34 @@ readonly class RecordService
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
|
|
||||||
$queryResult = $this->query->filter(["id" => $id])->run();
|
$record = $this->query->filter(["id" => $id])->run()->records->first();
|
||||||
$record = $queryResult->getQueryRecords()->records[0] ?? null;
|
|
||||||
|
|
||||||
if (empty($record)) {
|
if (empty($record)) {
|
||||||
throw new LucentException("Record id is missing");
|
throw new LucentException("Record id is missing");
|
||||||
}
|
}
|
||||||
$formattedData = $this->inputFormatter->fill($record->_sys->schema, new RecordData($data));
|
$formattedData = $this->inputFormatter->fill($record->schema, new RecordData($data));
|
||||||
|
|
||||||
if ($updateEdges) {
|
if ($updateEdges) {
|
||||||
$uniqueEdges = collect($edges)
|
$uniqueEdges = collect($edges)
|
||||||
->map(function ($edge, $index) {
|
->map(function ($edge, $index) {
|
||||||
|
$edge["rank"] = $index;
|
||||||
$edgeData = (array)(new Edge(...$edge));
|
$edgeData = (array)(new Edge(...$edge));
|
||||||
$edgeData["rank"] = $index;
|
|
||||||
return $edgeData;
|
return $edgeData;
|
||||||
})
|
})
|
||||||
->unique(fn($e) => $e['field'] . $e['source'] . $e['target'] . $e['sourceSchema'])
|
->unique(fn($e) => $e['field'] . $e['source'] . $e['target'] . $e['sourceSchema'])
|
||||||
->values()->toArray();
|
->values()->toArray();
|
||||||
$uniqueEdgesCollection = EdgeCollection::fromArray($uniqueEdges);
|
$uniqueEdgesCollection = EdgeCollection::fromArray($uniqueEdges);
|
||||||
$errors = $this->recordValidator->check($record->_sys->schema, $formattedData, $uniqueEdgesCollection);
|
$errors = $this->recordValidator->check($record->schema, $formattedData, $uniqueEdgesCollection);
|
||||||
} else {
|
} else {
|
||||||
$errors = $this->recordValidator->check($record->_sys->schema, $formattedData, null);
|
$errors = $this->recordValidator->check($record->schema, $formattedData, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$newRecord = new Record(
|
$newRecord = new Record(
|
||||||
id: $record->id,
|
id: $record->id,
|
||||||
_sys: $record->_sys->update($this->authService->currentUserId(), $status),
|
schema: $record->schema,
|
||||||
|
status: Status::from($status),
|
||||||
|
_sys: $record->_sys->update($this->authService->currentUserId()),
|
||||||
data: $record->data->merge($formattedData),
|
data: $record->data->merge($formattedData),
|
||||||
_file: $record->_file,
|
_file: $record->_file,
|
||||||
);
|
);
|
||||||
@@ -162,8 +163,7 @@ readonly class RecordService
|
|||||||
array $recordsIds,
|
array $recordsIds,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
$recordsStatus = (new RecordStatus($status));
|
RecordRepo::updateStatusBulk(Status::from($status), $recordsIds);
|
||||||
RecordRepo::updateStatusBulk($recordsStatus, $recordsIds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,18 +175,17 @@ readonly class RecordService
|
|||||||
string $recordId,
|
string $recordId,
|
||||||
): string
|
): string
|
||||||
{
|
{
|
||||||
$queryResult = $this->query
|
$graph = $this->query
|
||||||
->filter(["id" => $recordId])
|
->filter(["id" => $recordId])
|
||||||
->limit(1)
|
->limit(1)
|
||||||
->childrenDepth(1)
|
->childrenDepth(1)
|
||||||
->runWithCount();
|
->run();
|
||||||
|
|
||||||
|
$record = $graph->records->first();
|
||||||
$graph = $queryResult->getQueryRecords();
|
|
||||||
$record = $graph->records[0] ?? null;
|
|
||||||
if (empty($record)) {
|
if (empty($record)) {
|
||||||
throw new LucentException("Record id is missing");
|
throw new LucentException("Record id is missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
$newRecordId = (string)Str::uuid();
|
$newRecordId = (string)Str::uuid();
|
||||||
$newEdgesData = $graph->edges
|
$newEdgesData = $graph->edges
|
||||||
->filter(fn(Edge $edge) => $edge->source == $recordId)
|
->filter(fn(Edge $edge) => $edge->source == $recordId)
|
||||||
@@ -199,7 +198,7 @@ readonly class RecordService
|
|||||||
$record->id = $newRecordId;
|
$record->id = $newRecordId;
|
||||||
|
|
||||||
return $this->create(
|
return $this->create(
|
||||||
schemaName: $record->_sys->schema,
|
schemaName: $record->schema,
|
||||||
data: $record->data->toArray(),
|
data: $record->data->toArray(),
|
||||||
id: $record->id,
|
id: $record->id,
|
||||||
file: $record->_file?->toArray() ?? [],
|
file: $record->_file?->toArray() ?? [],
|
||||||
@@ -223,18 +222,14 @@ readonly class RecordService
|
|||||||
* @throws ValidatorException
|
* @throws ValidatorException
|
||||||
*/
|
*/
|
||||||
public function rollback(
|
public function rollback(
|
||||||
string $userId,
|
|
||||||
string $recordId,
|
string $recordId,
|
||||||
int $version,
|
int $version,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
$revision = $this->revisionService->getByRecordIdAndVersion($recordId, $version)->get();
|
$revision = $this->revisionService->getByRecordIdAndVersion($recordId, $version)->get();
|
||||||
$this->update(
|
$this->update(
|
||||||
userId: $userId,
|
|
||||||
id: $revision->recordId,
|
id: $revision->recordId,
|
||||||
data: $revision->data->toArray(),
|
data: $revision->data->toArray(),
|
||||||
status: $revision->_sys->status,
|
|
||||||
updateEdges: false
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +249,9 @@ readonly class RecordService
|
|||||||
|
|
||||||
return new Record(
|
return new Record(
|
||||||
id: Id::new(),
|
id: Id::new(),
|
||||||
_sys: System::newRecord($schema, $userId),
|
schema: $schema->name,
|
||||||
|
status: Status::DRAFT,
|
||||||
|
_sys: System::newRecord($userId),
|
||||||
data: $formattedData,
|
data: $formattedData,
|
||||||
_file: null,
|
_file: null,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Record;
|
|
||||||
|
|
||||||
class RecordStatus
|
|
||||||
{
|
|
||||||
|
|
||||||
private string $value;
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
public readonly ?string $status = null,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (empty($status)) {
|
|
||||||
$this->value = "draft";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$validStatuses = ["trashed", "published", "draft"];
|
|
||||||
if (!in_array($status, $validStatuses)) {
|
|
||||||
$status = "draft";
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->value = $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function value(): string
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lucent\Record;
|
||||||
|
|
||||||
|
enum Status: string
|
||||||
|
{
|
||||||
|
case DRAFT = "draft";
|
||||||
|
case PUBLISHED = "published";
|
||||||
|
case TRASHED = "trashed";
|
||||||
|
}
|
||||||
+8
-17
@@ -5,18 +5,16 @@ namespace Lucent\Record;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Lucent\Schema\Schema;
|
use Lucent\Schema\Schema;
|
||||||
|
|
||||||
class System
|
readonly class System
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
function __construct(
|
function __construct(
|
||||||
public readonly string $schema,
|
public int $version,
|
||||||
public readonly int $version,
|
public string $createdBy,
|
||||||
public readonly string $status,
|
public string $updatedBy,
|
||||||
public readonly string $createdBy,
|
public string $createdAt,
|
||||||
public readonly string $updatedBy,
|
public string $updatedAt,
|
||||||
public readonly string $createdAt,
|
|
||||||
public readonly string $updatedAt,
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -26,9 +24,7 @@ class System
|
|||||||
public static function fromArray(array $data): System
|
public static function fromArray(array $data): System
|
||||||
{
|
{
|
||||||
return new System(
|
return new System(
|
||||||
schema: data_get($data, "schema"),
|
|
||||||
version: data_get($data, "version"),
|
version: data_get($data, "version"),
|
||||||
status: data_get($data, "status"),
|
|
||||||
createdBy: data_get($data, "createdBy"),
|
createdBy: data_get($data, "createdBy"),
|
||||||
updatedBy: data_get($data, "updatedBy"),
|
updatedBy: data_get($data, "updatedBy"),
|
||||||
createdAt: data_get($data, "createdAt"),
|
createdAt: data_get($data, "createdAt"),
|
||||||
@@ -37,13 +33,11 @@ class System
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function newRecord(Schema $schema, string $userId, ?string $status = null): System
|
public static function newRecord(string $userId): System
|
||||||
{
|
{
|
||||||
$now = Carbon::now()->toJson();
|
$now = Carbon::now()->toJson();
|
||||||
return new System(
|
return new System(
|
||||||
schema: $schema->name,
|
|
||||||
version: 1,
|
version: 1,
|
||||||
status: (new RecordStatus($status))->value(),
|
|
||||||
createdBy: $userId,
|
createdBy: $userId,
|
||||||
updatedBy: $userId,
|
updatedBy: $userId,
|
||||||
createdAt: $now,
|
createdAt: $now,
|
||||||
@@ -52,14 +46,11 @@ class System
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function update(string $userId, ?string $status = null): System
|
public function update(string $userId): System
|
||||||
{
|
{
|
||||||
$now = Carbon::now()->toJson();
|
$now = Carbon::now()->toJson();
|
||||||
$newStatus = $status ?? $this->status;
|
|
||||||
return new System(
|
return new System(
|
||||||
schema: $this->schema,
|
|
||||||
version: $this->version + 1,
|
version: $this->version + 1,
|
||||||
status: (new RecordStatus($newStatus))->value(),
|
|
||||||
createdBy: $this->createdBy,
|
createdBy: $this->createdBy,
|
||||||
updatedBy: $userId,
|
updatedBy: $userId,
|
||||||
createdAt: $this->createdAt,
|
createdAt: $this->createdAt,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ readonly class Revision
|
|||||||
function __construct(
|
function __construct(
|
||||||
public string $id,
|
public string $id,
|
||||||
public string $recordId,
|
public string $recordId,
|
||||||
|
public string $schema,
|
||||||
public System $_sys,
|
public System $_sys,
|
||||||
public RecordData $data,
|
public RecordData $data,
|
||||||
public ?File $_file = null,
|
public ?File $_file = null,
|
||||||
@@ -22,12 +23,6 @@ readonly class Revision
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toArray(): array
|
|
||||||
{
|
|
||||||
return json_decode(json_encode($this), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static function fromDB(stdClass $data): Revision
|
public static function fromDB(stdClass $data): Revision
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -42,6 +37,7 @@ readonly class Revision
|
|||||||
return new Revision(
|
return new Revision(
|
||||||
id: $data->id,
|
id: $data->id,
|
||||||
recordId: $data->recordId,
|
recordId: $data->recordId,
|
||||||
|
schema: $data->schema,
|
||||||
_sys: System::fromArray(json_decode($data->_sys, true)),
|
_sys: System::fromArray(json_decode($data->_sys, true)),
|
||||||
data: new RecordData(json_decode($data->data, true)),
|
data: new RecordData(json_decode($data->data, true)),
|
||||||
_file: $file,
|
_file: $file,
|
||||||
@@ -53,6 +49,7 @@ readonly class Revision
|
|||||||
return [
|
return [
|
||||||
"id" => $this->id,
|
"id" => $this->id,
|
||||||
"recordId" => $this->recordId,
|
"recordId" => $this->recordId,
|
||||||
|
"schema" => $this->schema,
|
||||||
"_sys" => json_encode($this->_sys),
|
"_sys" => json_encode($this->_sys),
|
||||||
"_file" => json_encode($this->_file),
|
"_file" => json_encode($this->_file),
|
||||||
"data" => json_encode($this->data),
|
"data" => json_encode($this->data),
|
||||||
@@ -65,6 +62,7 @@ readonly class Revision
|
|||||||
return new Revision(
|
return new Revision(
|
||||||
id: (string)Str::uuid(),
|
id: (string)Str::uuid(),
|
||||||
recordId: $record->id,
|
recordId: $record->id,
|
||||||
|
schema: $record->schema,
|
||||||
_sys: $record->_sys,
|
_sys: $record->_sys,
|
||||||
data: $record->data,
|
data: $record->data,
|
||||||
_file: $record->_file,
|
_file: $record->_file,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ class CollectionSchema implements Schema
|
|||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<FieldInterface> $fields
|
||||||
* @param array<string> $visible
|
* @param array<string> $visible
|
||||||
|
* @param array<string> $fields
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
public string $label,
|
public string $label,
|
||||||
public array $visible,
|
public array $visible,
|
||||||
|
public array $groups,
|
||||||
public Collection $fields,
|
public Collection $fields,
|
||||||
public bool $isEntry = false,
|
public bool $isEntry = false,
|
||||||
public string $color = "",
|
public string $color = "",
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ class FilesSchema implements Schema
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Collection<FieldInterface> $fields
|
* @param Collection<FieldInterface> $fields
|
||||||
|
* @param array<string> $groups
|
||||||
*/
|
*/
|
||||||
function __construct(
|
function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
public string $label,
|
public string $label,
|
||||||
public Collection $fields,
|
public Collection $fields,
|
||||||
public string $path,
|
public string $path,
|
||||||
|
public array $groups,
|
||||||
public bool $isEntry = false,
|
public bool $isEntry = false,
|
||||||
public string $color = "",
|
public string $color = "",
|
||||||
public string $titleTemplate = "",
|
public string $titleTemplate = "",
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent\Schema;
|
|
||||||
|
|
||||||
use Lucent\Field\Field;
|
|
||||||
use Lucent\View\View;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
**/
|
|
||||||
function visibleFields(Schema $schema, ?View $view = null): array
|
|
||||||
{
|
|
||||||
|
|
||||||
$visibleFieldNames = $schema->visible;
|
|
||||||
if (!empty($view)) {
|
|
||||||
$visibleFieldNames = $view->visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $schema->fields
|
|
||||||
->filter(function (Field $f) use ($visibleFieldNames) {
|
|
||||||
|
|
||||||
if ($f->trashed || $f->ui == "tab") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $visibleFieldNames->contains($f->name->value);
|
|
||||||
})
|
|
||||||
->values()
|
|
||||||
->map(fn(Field $f) => $f->name->value)
|
|
||||||
->toArray();
|
|
||||||
}
|
|
||||||
@@ -20,19 +20,21 @@ class SchemaService
|
|||||||
name: $schemaArr["name"],
|
name: $schemaArr["name"],
|
||||||
label: $schemaArr["label"],
|
label: $schemaArr["label"],
|
||||||
visible: $schemaArr["visible"] ?? [],
|
visible: $schemaArr["visible"] ?? [],
|
||||||
|
groups: $schemaArr["groups"] ?? [],
|
||||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
||||||
isEntry: $schemaArr["isEntry"],
|
isEntry: $schemaArr["isEntry"] ?? false,
|
||||||
color: $schemaArr["color"],
|
color: $schemaArr["color"] ?? "",
|
||||||
titleTemplate: $schemaArr["titleTemplate"],
|
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||||
),
|
),
|
||||||
"files" => new FilesSchema(
|
"files" => new FilesSchema(
|
||||||
name: $schemaArr["name"],
|
name: $schemaArr["name"],
|
||||||
label: $schemaArr["label"],
|
label: $schemaArr["label"],
|
||||||
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
fields: (new Collection($schemaArr["fields"]))->map([$this, 'mapFields']),
|
||||||
path: $schemaArr["path"],
|
path: $schemaArr["path"] ?? $schemaArr["name"],
|
||||||
isEntry: $schemaArr["isEntry"],
|
groups: $schemaArr["groups"] ?? [],
|
||||||
color: $schemaArr["color"],
|
isEntry: $schemaArr["isEntry"] ?? false,
|
||||||
titleTemplate: $schemaArr["titleTemplate"]
|
color: $schemaArr["color"] ?? "",
|
||||||
|
titleTemplate: $schemaArr["titleTemplate"] ?? "",
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Lucent\Field;
|
namespace Lucent\Schema;
|
||||||
|
|
||||||
readonly class System
|
readonly class System
|
||||||
{
|
{
|
||||||
@@ -26,7 +26,7 @@ readonly class System
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"_sys.status" => new System(
|
"_sys.status" => new System(
|
||||||
name: "_sys.status",
|
name: "status",
|
||||||
label: "Status",
|
label: "Status",
|
||||||
ui: "status",
|
ui: "status",
|
||||||
files: false,
|
files: false,
|
||||||
@@ -14,7 +14,7 @@ class StaticGenerator
|
|||||||
$filepath = public_path($path . "/index.html");
|
$filepath = public_path($path . "/index.html");
|
||||||
|
|
||||||
if (!file_exists(pathinfo($filepath, PATHINFO_DIRNAME))) {
|
if (!file_exists(pathinfo($filepath, PATHINFO_DIRNAME))) {
|
||||||
$this->make_dir(pathinfo($filepath, PATHINFO_DIRNAME));
|
make_dir_r(pathinfo($filepath, PATHINFO_DIRNAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
file_put_contents($filepath, $html);
|
file_put_contents($filepath, $html);
|
||||||
@@ -35,8 +35,5 @@ class StaticGenerator
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function make_dir(string $path): void
|
|
||||||
{
|
|
||||||
is_dir($path) || mkdir($path, 0777, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Lucent;
|
|
||||||
|
|
||||||
|
|
||||||
class Support
|
|
||||||
{
|
|
||||||
public static function toArray(mixed $data):array
|
|
||||||
{
|
|
||||||
return \json_decode(\json_encode($data), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,10 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>@yield('title') - Lucent Data Platform</title>
|
<title>@yield('title') - Lucent Data Platform</title>
|
||||||
@vite(['resources/js/app.js'])
|
@php
|
||||||
|
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
|
||||||
|
@endphp
|
||||||
|
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -6,7 +6,14 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>@yield('title') - Lucent Data Platform</title>
|
<title>@yield('title') - Lucent Data Platform</title>
|
||||||
@vite(['resources/js/app.js'])
|
<!-- if development -->
|
||||||
|
@php
|
||||||
|
echo '<script type="module" crossorigin src="http://127.0.0.1:5173/@vite/client"></script>';
|
||||||
|
@endphp
|
||||||
|
<script type="module" crossorigin src="http://127.0.0.1:5173/main.js"></script>
|
||||||
|
<!-- if production -->
|
||||||
|
{{-- <link rel="stylesheet" href="/assets/{{ manifest['main.js'].css }}" />
|
||||||
|
<script type="module" src="/assets/{{ manifest['main.js'].file }}"></script> --}}
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -31,3 +31,9 @@ if (!function_exists('toArray')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!function_exists('make_dir_r')) {
|
||||||
|
function make_dir_r(string $path): void
|
||||||
|
{
|
||||||
|
is_dir($path) || mkdir($path, 0777, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user