mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-08 06:42:39 +02:00
remove url from share and add auth (#260)
This commit is contained in:
parent
a7abdc43a5
commit
041ab25b7b
3 changed files with 20 additions and 25 deletions
|
|
@ -5,6 +5,7 @@ import { nanoid } from "nanoid";
|
||||||
import { Workflow } from "@/app/lib/types/workflow_types";
|
import { Workflow } from "@/app/lib/types/workflow_types";
|
||||||
import { db } from "@/app/lib/mongodb";
|
import { db } from "@/app/lib/mongodb";
|
||||||
import { SHARED_WORKFLOWS_COLLECTION } from "@/src/infrastructure/repositories/mongodb.shared-workflows.indexes";
|
import { SHARED_WORKFLOWS_COLLECTION } from "@/src/infrastructure/repositories/mongodb.shared-workflows.indexes";
|
||||||
|
import { requireAuth } from "@/app/lib/auth";
|
||||||
|
|
||||||
const DEFAULT_TTL_SECONDS = 60 * 60 * 24; // 24 hours
|
const DEFAULT_TTL_SECONDS = 60 * 60 * 24; // 24 hours
|
||||||
|
|
||||||
|
|
@ -26,6 +27,8 @@ function validateWorkflowJson(obj: unknown) {
|
||||||
|
|
||||||
export async function createSharedWorkflowFromJson(json: string): Promise<{ id: string; ttlSeconds: number; }>
|
export async function createSharedWorkflowFromJson(json: string): Promise<{ id: string; ttlSeconds: number; }>
|
||||||
{
|
{
|
||||||
|
// Require an authenticated user (respects guest mode when auth is disabled)
|
||||||
|
await requireAuth();
|
||||||
const obj = JSON.parse(json);
|
const obj = JSON.parse(json);
|
||||||
const workflow = validateWorkflowJson(obj);
|
const workflow = validateWorkflowJson(obj);
|
||||||
|
|
||||||
|
|
@ -38,23 +41,18 @@ export async function createSharedWorkflowFromJson(json: string): Promise<{ id:
|
||||||
return { id, ttlSeconds: DEFAULT_TTL_SECONDS };
|
return { id, ttlSeconds: DEFAULT_TTL_SECONDS };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadSharedWorkflow(idOrUrl: string): Promise<z.infer<typeof Workflow>> {
|
/**
|
||||||
// If it's an http(s) URL, fetch JSON and validate
|
* Load a shared workflow by ephemeral share id stored in MongoDB.
|
||||||
const isHttp = idOrUrl.startsWith('http://') || idOrUrl.startsWith('https://');
|
* Expected when the query param `shared` is present in the UI.
|
||||||
if (isHttp) {
|
*/
|
||||||
const resp = await fetch(idOrUrl, { cache: 'no-store' });
|
export async function loadSharedWorkflow(id: string): Promise<z.infer<typeof Workflow>> {
|
||||||
if (!resp.ok) {
|
// Ensure caller is authenticated (guest allowed when auth disabled)
|
||||||
throw new Error(`Failed to fetch URL: ${resp.status} ${resp.statusText}`);
|
await requireAuth();
|
||||||
}
|
|
||||||
const text = await resp.text();
|
|
||||||
const obj = JSON.parse(text);
|
|
||||||
return validateWorkflowJson(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, look up by shared id in MongoDB
|
// Look up by shared id in MongoDB
|
||||||
const coll = db.collection<SharedWorkflowDoc>(SHARED_WORKFLOWS_COLLECTION);
|
const coll = db.collection<SharedWorkflowDoc>(SHARED_WORKFLOWS_COLLECTION);
|
||||||
const doc = await coll.findOne(
|
const doc = await coll.findOne(
|
||||||
{ _id: idOrUrl },
|
{ _id: id },
|
||||||
{ projection: { workflow: 1, expiresAt: 1 } }
|
{ projection: { workflow: 1, expiresAt: 1 } }
|
||||||
);
|
);
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
|
|
@ -65,4 +63,3 @@ export async function loadSharedWorkflow(idOrUrl: string): Promise<z.infer<typeo
|
||||||
}
|
}
|
||||||
return validateWorkflowJson(doc.workflow);
|
return validateWorkflowJson(doc.workflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -301,13 +301,12 @@ export function BuildAssistantSection() {
|
||||||
const urlPrompt = searchParams.get('prompt');
|
const urlPrompt = searchParams.get('prompt');
|
||||||
const urlTemplate = searchParams.get('template');
|
const urlTemplate = searchParams.get('template');
|
||||||
const sharedId = searchParams.get('shared');
|
const sharedId = searchParams.get('shared');
|
||||||
const importUrl = searchParams.get('importUrl');
|
|
||||||
|
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
if (sharedId || importUrl) {
|
if (sharedId) {
|
||||||
try {
|
try {
|
||||||
setAutoCreateLoading(true);
|
setAutoCreateLoading(true);
|
||||||
const workflowObj = await loadSharedWorkflow(sharedId || importUrl!);
|
const workflowObj = await loadSharedWorkflow(sharedId);
|
||||||
await createProjectFromJsonWithOptions({
|
await createProjectFromJsonWithOptions({
|
||||||
workflowJson: JSON.stringify(workflowObj),
|
workflowJson: JSON.stringify(workflowObj),
|
||||||
router,
|
router,
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,6 @@ export function CreateProject({ defaultName, onOpenProjectPane, isProjectPaneOpe
|
||||||
const urlPrompt = searchParams.get('prompt');
|
const urlPrompt = searchParams.get('prompt');
|
||||||
const urlTemplate = searchParams.get('template');
|
const urlTemplate = searchParams.get('template');
|
||||||
const sharedId = searchParams.get('shared');
|
const sharedId = searchParams.get('shared');
|
||||||
const importUrl = searchParams.get('importUrl');
|
|
||||||
|
|
||||||
// Add this effect to update name when defaultName changes
|
// Add this effect to update name when defaultName changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -168,13 +167,13 @@ export function CreateProject({ defaultName, onOpenProjectPane, isProjectPaneOpe
|
||||||
// Add effect to handle URL parameters for auto-creation
|
// Add effect to handle URL parameters for auto-creation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleAutoCreate = async () => {
|
const handleAutoCreate = async () => {
|
||||||
// Auto-create from template/prompt, or import from shared/id/url
|
// Auto-create from template/prompt, or import from shared id
|
||||||
if ((urlPrompt || urlTemplate || sharedId || importUrl) && !importLoading && !autoCreateLoading) {
|
if ((urlPrompt || urlTemplate || sharedId) && !importLoading && !autoCreateLoading) {
|
||||||
setAutoCreateLoading(true);
|
setAutoCreateLoading(true);
|
||||||
try {
|
try {
|
||||||
if (sharedId || importUrl) {
|
if (sharedId) {
|
||||||
// Load workflow via server action (supports id or URL)
|
// Load workflow via server action (by id)
|
||||||
const workflowObj = await loadSharedWorkflow(sharedId || importUrl!);
|
const workflowObj = await loadSharedWorkflow(sharedId);
|
||||||
await createProjectFromJsonWithOptions({
|
await createProjectFromJsonWithOptions({
|
||||||
workflowJson: JSON.stringify(workflowObj),
|
workflowJson: JSON.stringify(workflowObj),
|
||||||
router,
|
router,
|
||||||
|
|
@ -203,7 +202,7 @@ export function CreateProject({ defaultName, onOpenProjectPane, isProjectPaneOpe
|
||||||
};
|
};
|
||||||
|
|
||||||
handleAutoCreate();
|
handleAutoCreate();
|
||||||
}, [urlPrompt, urlTemplate, sharedId, importUrl, importLoading, autoCreateLoading, router]);
|
}, [urlPrompt, urlTemplate, sharedId, importLoading, autoCreateLoading, router]);
|
||||||
|
|
||||||
// Inject glow animation styles
|
// Inject glow animation styles
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue