mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
@@ -12,6 +12,7 @@
|
||||
***********************************************************************************************************************************************************************/
|
||||
"use strict";
|
||||
|
||||
const { Op } = require("sequelize");
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const R = require("../../utils/response.util");
|
||||
@@ -29,6 +30,21 @@ function resolveIp(req) {
|
||||
return req.ip ?? req.socket?.remoteAddress ?? "unknown";
|
||||
}
|
||||
|
||||
function signToken(asset, userId, ip) {
|
||||
return jwt.sign(
|
||||
{
|
||||
asset_id: asset.asset_id,
|
||||
user_id: userId,
|
||||
storage_key: asset.storage_key,
|
||||
file_type: asset.file_type,
|
||||
mime_type: asset.mime_type,
|
||||
ip,
|
||||
},
|
||||
MEDIA_SECRET,
|
||||
{ expiresIn: TOKEN_TTL_SEC }
|
||||
);
|
||||
}
|
||||
|
||||
// ─── POST /admin/media/token ──────────────────────────────────────────────────
|
||||
|
||||
exports.issueToken = async (req, res) => {
|
||||
@@ -51,20 +67,8 @@ exports.issueToken = async (req, res) => {
|
||||
return R.error(res, "Token flow is for S3 assets only. Use the raw file_url for other providers.", 400);
|
||||
}
|
||||
|
||||
const ip = resolveIp(req);
|
||||
|
||||
const token = jwt.sign(
|
||||
{
|
||||
asset_id,
|
||||
user_id: req.user.user_id,
|
||||
storage_key: asset.storage_key,
|
||||
file_type: asset.file_type,
|
||||
mime_type: asset.mime_type,
|
||||
ip,
|
||||
},
|
||||
MEDIA_SECRET,
|
||||
{ expiresIn: TOKEN_TTL_SEC }
|
||||
);
|
||||
const ip = resolveIp(req);
|
||||
const token = signToken(asset, req.user.user_id, ip);
|
||||
|
||||
// ── Presign thumbnail URL so the browser can load it directly ─────────────
|
||||
let thumbnail_url = null;
|
||||
@@ -88,3 +92,39 @@ exports.issueToken = async (req, res) => {
|
||||
return R.error(res, "Could not issue media token.", 500);
|
||||
}
|
||||
};
|
||||
|
||||
// ─── POST /admin/media/tokens (batch) ───────────────────────────────────────
|
||||
//
|
||||
// Accepts { asset_ids: [id, ...] } — S3 assets only, max 50.
|
||||
// Returns { tokens: { [asset_id]: token } }
|
||||
// One round-trip instead of N per-card requests.
|
||||
|
||||
exports.issueTokensBatch = async (req, res) => {
|
||||
try {
|
||||
const { asset_ids } = req.body;
|
||||
if (!Array.isArray(asset_ids) || !asset_ids.length)
|
||||
return R.error(res, "asset_ids must be a non-empty array.", 400);
|
||||
if (asset_ids.length > 50)
|
||||
return R.error(res, "Maximum 50 asset_ids per batch.", 400);
|
||||
|
||||
const assets = await mdl_Assets.findAll({
|
||||
where: {
|
||||
asset_id: { [Op.in]: asset_ids },
|
||||
storage_provider: "s3",
|
||||
deletedAt: null,
|
||||
},
|
||||
attributes: ["asset_id", "file_type", "storage_key", "mime_type"],
|
||||
});
|
||||
|
||||
const ip = resolveIp(req);
|
||||
const tokens = {};
|
||||
for (const asset of assets) {
|
||||
tokens[String(asset.asset_id)] = signToken(asset, req.user.user_id, ip);
|
||||
}
|
||||
|
||||
return R.success(res, "Tokens issued.", { tokens });
|
||||
} catch (err) {
|
||||
console.error("[ADMIN][MEDIA][TOKENS BATCH]", err);
|
||||
return R.error(res, "Could not issue media tokens.", 500);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user