Merge pull request #2434 from NHClaessens/feature-share-link-redirect-path

feat: Add path setting to share links (resourceAccessToken)
This commit is contained in:
Owen Schwartz
2026-05-28 20:28:28 -07:00
committed by GitHub
6 changed files with 32 additions and 3 deletions

View File

@@ -176,6 +176,7 @@
"shareErrorCreateDescription": "An error occurred while creating the share link",
"shareCreateDescription": "Anyone with this link can access the resource",
"shareTitleOptional": "Title (optional)",
"sharePathOptional": "Path (optional)",
"expireIn": "Expire In",
"neverExpire": "Never expire",
"shareExpireDescription": "Expiration time is how long the link will be usable and provide access to the resource. After this time, the link will no longer work, and users who used this link will lose access to the resource.",

View File

@@ -772,6 +772,7 @@ export const resourceAccessToken = pgTable("resourceAccessToken", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
path: varchar("path"),
tokenHash: varchar("tokenHash").notNull(),
sessionLength: bigint("sessionLength", { mode: "number" }).notNull(),
expiresAt: bigint("expiresAt", { mode: "number" }),

View File

@@ -1101,6 +1101,7 @@ export const resourceAccessToken = sqliteTable("resourceAccessToken", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
path: text("path"),
tokenHash: text("tokenHash").notNull(),
sessionLength: integer("sessionLength").notNull(),
expiresAt: integer("expiresAt"),

View File

@@ -27,6 +27,7 @@ import { OpenAPITags, registry } from "@server/openApi";
export const generateAccessTokenBodySchema = z.strictObject({
validForSeconds: z.int().positive().optional(), // seconds
title: z.string().optional(),
path: z.string().optional(),
description: z.string().optional()
});
@@ -85,7 +86,7 @@ export async function generateAccessToken(
}
const { resourceId } = parsedParams.data;
const { validForSeconds, title, description } = parsedBody.data;
const { validForSeconds, title, path, description } = parsedBody.data;
const [resource] = await db
.select()
@@ -121,6 +122,7 @@ export async function generateAccessToken(
expiresAt: expiresAt || null,
sessionLength: sessionLength,
title: title || null,
path: path || null,
description: description || null,
createdAt: new Date().getTime()
})
@@ -131,6 +133,7 @@ export async function generateAccessToken(
expiresAt: resourceAccessToken.expiresAt,
sessionLength: resourceAccessToken.sessionLength,
title: resourceAccessToken.title,
path: resourceAccessToken.path,
description: resourceAccessToken.description,
createdAt: resourceAccessToken.createdAt
})

View File

@@ -167,7 +167,12 @@ export async function authWithAccessToken(
let redirectUrl = `${resource.ssl ? "https" : "http"}://${resource.fullDomain}`;
const postAuthPath = normalizePostAuthPath(resource.postAuthPath);
if (postAuthPath) {
if (tokenItem.path) {
// add the path from the access token to the redirect URL, ensuring there is exactly one slash between the domain and the path
redirectUrl =
redirectUrl.replace(/\/?$/, "/") +
tokenItem.path.replace(/^\/?/, "");
} else if (postAuthPath) {
redirectUrl = redirectUrl + postAuthPath;
}

View File

@@ -112,6 +112,7 @@ export default function CreateShareLinkForm({
resourceId: z.number({ message: t("shareErrorSelectResource") }),
resourceName: z.string(),
resourceUrl: z.string(),
path: z.string().optional(),
timeUnit: z.string(),
timeValue: z.coerce.number<number>().int().positive().min(1),
title: z.string().optional()
@@ -172,7 +173,8 @@ export default function CreateShareLinkForm({
resource:
values.resourceName ||
"Resource" + values.resourceId
})
}),
path: values.path
}
)
.catch((e) => {
@@ -320,6 +322,22 @@ export default function CreateShareLinkForm({
)}
/>
<FormField
control={form.control}
name="path"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("sharePathOptional")}
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="space-y-4">
<div className="space-y-2">
<FormLabel>