Function bodies 103 total
mergeRows function · javascript · L18-L22 (5 LOC)components/ProjectsDashboard.js
function mergeRows(existing, incoming) {
const map = new Map(existing.map((row) => [row.id, row]));
incoming.forEach((row) => { map.set(row.id, row); });
return Array.from(map.values());
}formatDate function · javascript · L24-L29 (6 LOC)components/ProjectsDashboard.js
function formatDate(value) {
if (!value) return "-";
const d = new Date(value);
if (Number.isNaN(d.getTime())) return "-";
return d.toLocaleString();
}ProjectsDashboard function · javascript · L31-L289 (259 LOC)components/ProjectsDashboard.js
export default function ProjectsDashboard({
authToken,
currentUserId,
initialStatus = "",
initialTechnicianId = "",
}) {
const [rows, setRows] = useState([]);
const [role, setRole] = useState("viewer");
const [status, setStatus] = useState(initialStatus);
const [technicianId, setTechnicianId] = useState(initialTechnicianId);
const [search, setSearch] = useState("");
const [nextCursor, setNextCursor] = useState(null);
const [hasMore, setHasMore] = useState(false);
const [loading, setLoading] = useState(false);
const [loadingMore, setLoadingMore] = useState(false);
const [error, setError] = useState(null);
const sentinelRef = useRef(null);
const abortControllerRef = useRef(null);
const requestIdRef = useRef(0);
const apiClient = useMemo(() => createApiClient({ authToken }), [authToken]);
const fetchProjects = useCallback(async ({ cursor = null, append = false } = {}) => {
if (abortControllerRef.current) {
abortControllerRef.current.abortgetFileExtension function · javascript · L13-L16 (4 LOC)components/UploadPanel.js
function getFileExtension(fileName) {
const parts = String(fileName || "").toLowerCase().split(".");
return parts.length > 1 ? parts.pop() : "";
}normalizePreviewRows function · javascript · L19-L55 (37 LOC)components/UploadPanel.js
function normalizePreviewRows(rows, maxRows = 5) {
if (!Array.isArray(rows) || !rows.length) {
return { columns: [], rows: [] };
}
// Handle array of objects (standard CSV/JSON parse)
const objectRows = rows.filter((row) => row && typeof row === "object" && !Array.isArray(row));
if (objectRows.length) {
const columns = Array.from(
objectRows.slice(0, maxRows).reduce((set, row) => {
Object.keys(row).forEach((key) => set.add(key));
return set;
}, new Set())
);
const previewRows = objectRows.slice(0, maxRows).map((row, idx) => ({
__id: `${idx}`,
...row,
}));
return { columns, rows: previewRows };
}
// Handle array of arrays (raw Excel sheet)
const arrayRows = rows.filter(Array.isArray);
if (arrayRows.length) {
const header = arrayRows[0].map((v, idx) => String(v || `column_${idx + 1}`));
const dataRows = arrayRows.slice(1, maxRows + 1).map((row, rowIdx) => {
const out = { __id: `${rowIdx}` };parseSpreadsheetOrCsv function · javascript · L57-L80 (24 LOC)components/UploadPanel.js
async function parseSpreadsheetOrCsv(file, extension) {
if (extension === "csv") {
const parsed = await new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: resolve,
error: reject,
});
});
const data = Array.isArray(parsed?.data) ? parsed.data : [];
return normalizePreviewRows(data, 5);
}
const buffer = await file.arrayBuffer();
const workbook = read(buffer, { type: "array" });
const firstSheetName = workbook.SheetNames?.[0];
if (!firstSheetName) return { columns: [], rows: [] };
const sheet = workbook.Sheets[firstSheetName];
const rows = utils.sheet_to_json(sheet, { defval: "" });
return normalizePreviewRows(rows, 5);
}parsePdfMetadata function · javascript · L82-L90 (9 LOC)components/UploadPanel.js
async function parsePdfMetadata(file) {
try {
const data = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data }).promise;
return { type: "pdf", pageCount: pdf.numPages || null };
} catch {
return { type: "pdf", pageCount: null };
}
}Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
UploadPanel function · javascript · L92-L376 (285 LOC)components/UploadPanel.js
export default function UploadPanel({ authToken, projectId, table = "sites", fields = {}, onUploadComplete }) {
const apiClient = useMemo(() => createApiClient({ authToken }), [authToken]);
const [file, setFile] = useState(null);
const [fileType, setFileType] = useState("");
const [preview, setPreview] = useState({ kind: "none" });
const [loadingPreview, setLoadingPreview] = useState(false);
const [uploading, setUploading] = useState(false);
const [error, setError] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const [rowErrors, setRowErrors] = useState([]);
const objectUrlRef = useRef(null);
const uploadAbortRef = useRef(null);
// Cleanup object URLs and abort controllers on unmount
useEffect(() => {
return () => {
if (objectUrlRef.current) {
URL.revokeObjectURL(objectUrlRef.current);
objectUrlRef.current = null;
}
if (uploadAbortRef.current) {
uploadAbortRef.current.abort();
handleFileChange function · javascript · L122-L186 (65 LOC)components/UploadPanel.js
async function handleFileChange(event) {
const selected = event.target.files?.[0] || null;
// Reset state
setFile(null);
setFileType("");
setPreview({ kind: "none" });
setError("");
setSuccessMessage("");
setRowErrors([]);
// Cleanup previous preview resource
if (objectUrlRef.current) {
URL.revokeObjectURL(objectUrlRef.current);
objectUrlRef.current = null;
}
if (!selected) return;
const extension = getFileExtension(selected.name);
// Client-side validation
if (!ALLOWED_EXTENSIONS.has(extension)) {
setError("Unsupported file type. Allowed: .xlsx, .csv, .pdf, .jpeg, .jpg, .png");
return;
}
if (selected.size > MAX_FILE_BYTES) {
setError("File too large. Maximum size is 10MB.");
return;
}
setFile(selected);
setFileType(extension);
setLoadingPreview(true);
try {
// Generate Preview based on type
if (extension === "csv" || extension === "xlsx") {
handleUpload function · javascript · L188-L243 (56 LOC)components/UploadPanel.js
async function handleUpload() {
if (!file) {
setError("Choose a file first.");
return;
}
if (!projectId) {
setError("projectId is required before upload.");
return;
}
// Cancel previous upload if any
if (uploadAbortRef.current) uploadAbortRef.current.abort();
uploadAbortRef.current = new AbortController();
setUploading(true);
setError("");
setSuccessMessage("");
setRowErrors([]);
try {
const payload = await apiClient.uploadFile(
{ file, projectId, table, fields },
{ signal: uploadAbortRef.current.signal }
);
// Handle response payload
const errors = Array.isArray(payload?.errors) ? payload.errors : [];
setRowErrors(errors);
const status = String(payload?.status || (payload?.ok ? "success" : "error")).toLowerCase();
if (status === "error") {
setError(payload?.error || "Upload completed with errors.");
} else {
const inserted = patoSafeFilename function · javascript · L7-L9 (3 LOC)fileParser.js
function toSafeFilename(name){
return String(name || "upload.bin").replace(/[^a-zA-Z0-9._-]/g, "_");
}getStorageDescriptor function · javascript · L11-L21 (11 LOC)fileParser.js
function getStorageDescriptor(file, options = {}){
const prefix = String(options.storagePrefix || "uploads").replace(/\/$/, "");
const fileName = toSafeFilename(file?.name || "upload.bin");
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
return {
bucket: options.bucket || "site-media",
contentType: file?.type || "application/octet-stream",
byteSize: Number(file?.size || 0),
path: `${prefix}/${stamp}_${fileName}`,
};
}parseFile function · javascript · L23-L57 (35 LOC)fileParser.js
export async function parseFile(file, options = {}){
if (!file) throw new Error("file is required");
const fileType = String(file.name || "")
.split(".")
.pop()
.toLowerCase();
if (fileType === "csv"){
return new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: (results) => resolve(results.data || []),
error: (error) => reject(error),
});
});
}
if (fileType === "xlsx" || fileType === "xls"){
const data = await file.arrayBuffer();
const workbook = read(data);
const firstSheetName = workbook.SheetNames[0];
if (!firstSheetName) return [];
const worksheet = workbook.Sheets[firstSheetName];
return utils.sheet_to_json(worksheet, { defval: null });
}
if (fileType === "pdf"){
return extractTextFromPdf(file);
}
return parseFileFallback(file, options);
}extractTextFromPdf function · javascript · L59-L72 (14 LOC)fileParser.js
async function extractTextFromPdf(file){
const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const pages = [];
for (let i = 1; i <= pdf.numPages; i += 1){
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
const pageText = textContent.items.map((item) => item.str).join(" ").trim();
if (pageText) pages.push(pageText);
}
return [{ raw_text: pages.join("\n"), filename: file.name }];
}extractImageMetadata function · javascript · L74-L89 (16 LOC)fileParser.js
async function extractImageMetadata(file){
const metadata = { width: null, height: null };
if (typeof createImageBitmap === "function"){
try {
const bitmap = await createImageBitmap(file);
metadata.width = bitmap.width;
metadata.height = bitmap.height;
if (typeof bitmap.close === "function") bitmap.close();
} catch {
// Keep null dimensions if decode fails.
}
}
return metadata;
}Open data scored by Repobility · https://repobility.com
parseFileFallback function · javascript · L91-L127 (37 LOC)fileParser.js
export async function parseFileFallback(file, options = {}){
if (!file) throw new Error("file is required");
const mimeType = String(file.type || "").toLowerCase();
const isImage = mimeType.startsWith("image/");
const base = {
filename: file.name || "",
size: Number(file.size || 0),
type: file.type || "application/octet-stream",
lastModified: Number(file.lastModified || 0),
storage: getStorageDescriptor(file, options),
};
if (isImage){
const metadata = await extractImageMetadata(file);
return {
kind: "image",
...base,
metadata,
readyForStorage: true,
};
}
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => {
resolve({
kind: "binary",
...base,
base64: reader.result,
readyForStorage: true,
});
};
reader.readAsDataURL(file);
});
}handler function · javascript · L1-L23 (23 LOC)netlify/functions/app-config.js
export async function handler() {
const demoEnabled = String(process.env.DEMO_BOOTSTRAP_ENABLED || "").trim().toLowerCase();
const demoBootstrapOn = ["1", "true", "yes", "on"].includes(demoEnabled);
const showcaseEmails = String(process.env.LIVE_SHOWCASE_EMAILS || process.env.DEMO_SHOWCASE_EMAILS || "").trim();
return {
statusCode: 200,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
SUPABASE_URL: process.env.SUPABASE_URL,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY,
LIVE_MODE: true,
DEMO_SHOWCASE_ENABLED: process.env.DEMO_SHOWCASE_ENABLED,
DEMO_SHOWCASE_ALLOW_GLOBAL_REAL: process.env.DEMO_SHOWCASE_ALLOW_GLOBAL_REAL,
DEMO_SHOWCASE_ACCOUNT_ENABLED: process.env.DEMO_SHOWCASE_ACCOUNT_ENABLED,
LIVE_SHOWCASE_EMAILS: showcaseEmails || undefined,
DEMO_BOOTSTRAP_ENABLED: demoBootstrapOn ? "true" : undefined,
DEMO_BOOTSTRAP_ALLOW_WITH_LIVE_AUTH: demoBootstrapOn ? process.env.DEMO_BOOjson function · javascript · L25-L34 (10 LOC)netlify/functions/get-projects.js
function json(statusCode, payload, extraHeaders = {}) {
return {
statusCode,
headers: {
"Content-Type": "application/json",
...extraHeaders,
},
body: JSON.stringify(payload),
};
}getCacheHeaders function · javascript · L36-L41 (6 LOC)netlify/functions/get-projects.js
function getCacheHeaders() {
return {
"Cache-Control": "public, max-age=0, s-maxage=30, stale-while-revalidate=120",
"Netlify-CDN-Cache-Control": "public, max-age=30, stale-while-revalidate=120",
};
}isUuid function · javascript · L43-L45 (3 LOC)netlify/functions/get-projects.js
function isUuid(value) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(String(value || "").trim());
}parseCursor function · javascript · L47-L59 (13 LOC)netlify/functions/get-projects.js
function parseCursor(rawCursor) {
if (!rawCursor) return null;
try {
const decoded = Buffer.from(String(rawCursor), "base64").toString("utf8");
const parsed = JSON.parse(decoded);
if (!parsed?.created_at || !parsed?.id || !isUuid(parsed.id)) throw new Error("Invalid cursor");
const created = new Date(parsed.created_at);
if (Number.isNaN(created.getTime())) throw new Error("Invalid cursor");
return { created_at: created.toISOString(), id: parsed.id };
} catch {
throw new Error("Invalid cursor");
}
}encodeCursor function · javascript · L61-L64 (4 LOC)netlify/functions/get-projects.js
function encodeCursor(row) {
if (!row?.created_at || !row?.id) return null;
return Buffer.from(JSON.stringify({ created_at: row.created_at, id: row.id }), "utf8").toString("base64");
}parsePageSize function · javascript · L66-L70 (5 LOC)netlify/functions/get-projects.js
function parsePageSize(raw) {
const n = Number.parseInt(String(raw || DEFAULT_PAGE_SIZE), 10);
if (!Number.isFinite(n) || n < 1) return DEFAULT_PAGE_SIZE;
return Math.min(n, MAX_PAGE_SIZE);
}Repobility · severity-and-effort ranking · https://repobility.com
applySafeFilters function · javascript · L72-L104 (33 LOC)netlify/functions/get-projects.js
function applySafeFilters(query, params) {
const errors = [];
Object.keys(FILTER_CONFIG).forEach((key) => {
const rawValue = params[key];
if (rawValue == null || String(rawValue).trim() === "") return;
const config = FILTER_CONFIG[key];
if (!config?.column) {
errors.push(`Filter '${key}' is not supported.`);
return;
}
const value = String(rawValue).trim();
if (config.type === "uuid" && !isUuid(value)) {
errors.push(`Filter '${key}' must be a valid UUID.`);
return;
}
if (config.type === "enum_status") {
const normalized = value.toUpperCase();
if (!STATUS_WHITELIST.has(normalized)) {
errors.push(`Invalid status value. Allowed: ${Array.from(STATUS_WHITELIST).join(", ")}.`);
return;
}
query.eq(config.column, normalized);
return;
}
query.eq(config.column, value);
});
return { query, errors };
}json function · javascript · L14-L20 (7 LOC)netlify/functions/import-sites.js
function json(statusCode, payload){
return {
statusCode,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
};
}normalizeHeader function · javascript · L22-L28 (7 LOC)netlify/functions/import-sites.js
function normalizeHeader(value){
return String(value || "")
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, "_")
.replace(/^_+|_+$/g, "");
}findHeaderIndex function · javascript · L30-L33 (4 LOC)netlify/functions/import-sites.js
function findHeaderIndex(headers, candidates){
const lookup = new Set(candidates.map(normalizeHeader));
return headers.findIndex((h) => lookup.has(h));
}parseMultipart function · javascript · L35-L75 (41 LOC)netlify/functions/import-sites.js
function parseMultipart(event){
return new Promise((resolve, reject) => {
const contentType = event.headers["content-type"] || event.headers["Content-Type"] || "";
if (!contentType.includes("multipart/form-data")){
reject(new Error("Expected multipart/form-data upload."));
return;
}
const busboy = new Busboy({ headers: { "content-type": contentType } });
const fields = {};
const fileChunks = [];
let fileInfo = { filename: "", mime: "" };
busboy.on("field", (name, value) => {
fields[name] = value;
});
busboy.on("file", (fieldname, file, info, encoding, mimetype) => {
let filename = info;
let mime = mimetype;
if (info && typeof info === "object"){
filename = info.filename;
mime = info.mimeType;
}
fileInfo = { filename: filename || "", mime: mime || "" };
file.on("data", (data) => fileChunks.push(data));
});
busboy.on("finish", () => {
const buffer = fileChunksparseRowsFromFile function · javascript · L77-L91 (15 LOC)netlify/functions/import-sites.js
function parseRowsFromFile(buffer, filename){
const lower = String(filename || "").toLowerCase();
if (lower.endsWith(".xlsx")){
const workbook = XLSX.read(buffer, { type: "buffer" });
const sheetName = workbook.SheetNames[0];
if (!sheetName) return [];
const sheet = workbook.Sheets[sheetName];
return XLSX.utils.sheet_to_json(sheet, { header: 1, defval: "" });
}
if (lower.endsWith(".csv")){
const text = buffer.toString("utf8");
return parse(text, { relax_column_count: true, skip_empty_lines: true });
}
throw new Error("Unsupported file type. Upload .csv or .xlsx.");
}makeHeaders function · javascript · L68-L73 (6 LOC)netlify/functions/process-data.js
function makeHeaders(contentType){
return {
...CORS_HEADERS,
"Content-Type": contentType,
};
}response function · javascript · L75-L81 (7 LOC)netlify/functions/process-data.js
function response(statusCode, payload){
return {
statusCode,
headers: makeHeaders("application/json"),
body: JSON.stringify(payload),
};
}Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
normalizeHeader function · javascript · L83-L90 (8 LOC)netlify/functions/process-data.js
function normalizeHeader(value){
return String(value || "")
.trim()
.replace(/([a-z\d])([A-Z])/g, "$1_$2")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "_")
.replace(/^_+|_+$/g, "");
}parseMultipart function · javascript · L92-L133 (42 LOC)netlify/functions/process-data.js
function parseMultipart(event){
return new Promise((resolve, reject) => {
const contentType = event.headers["content-type"] || event.headers["Content-Type"] || "";
if (!contentType.includes("multipart/form-data")){
reject(new Error("Expected multipart/form-data upload."));
return;
}
const busboy = Busboy({ headers: { "content-type": contentType } });
const fields = {};
const fileChunks = [];
let fileInfo = { filename: "", mimeType: "" };
busboy.on("field", (name, value) => {
fields[name] = value;
});
busboy.on("file", (fieldName, file, info, encoding, mimetype) => {
void fieldName;
void encoding;
let filename = info;
let mimeType = mimetype;
if (info && typeof info === "object"){
filename = info.filename;
mimeType = info.mimeType;
}
fileInfo = { filename: filename || "", mimeType: mimeType || "" };
file.on("data", (chunk) => fileChunks.push(chunk));
});
parseGridRowsFromFile function · javascript · L135-L147 (13 LOC)netlify/functions/process-data.js
function parseGridRowsFromFile(buffer, filename){
const lower = String(filename || "").toLowerCase();
if (lower.endsWith(".xlsx") || lower.endsWith(".xls")){
const workbook = XLSX.read(buffer, { type: "buffer" });
const sheetName = workbook.SheetNames[0];
if (!sheetName) return [];
return XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], { header: 1, defval: "" });
}
if (lower.endsWith(".csv")){
return parse(buffer.toString("utf8"), { relax_column_count: true, skip_empty_lines: true });
}
throw new Error("Unsupported file type. Upload .csv, .xls, or .xlsx.");
}detectTable function · javascript · L149-L153 (5 LOC)netlify/functions/process-data.js
function detectTable(input){
const key = normalizeHeader(input);
if (TABLE_SCHEMAS[key]) return key;
throw new Error(`Unsupported table '${input}'. Supported tables: ${Object.keys(TABLE_SCHEMAS).join(", ")}.`);
}buildHeaderMap function · javascript · L155-L175 (21 LOC)netlify/functions/process-data.js
function buildHeaderMap(rawHeaders, schema){
const mapped = [];
const unknownHeaders = [];
const canonicalByAlias = new Map();
Object.entries(schema.columns).forEach(([column, meta]) => {
canonicalByAlias.set(normalizeHeader(column), column);
(meta.aliases || []).forEach((alias) => canonicalByAlias.set(normalizeHeader(alias), column));
});
rawHeaders.forEach((headerCell, idx) => {
const normalized = normalizeHeader(headerCell);
const mappedColumn = canonicalByAlias.get(normalized) || null;
mapped[idx] = mappedColumn;
if (!mappedColumn && normalized){
unknownHeaders.push({ header: String(headerCell || "").trim(), normalized, index: idx });
}
});
return { mapped, unknownHeaders };
}toNullIfBlank function · javascript · L177-L181 (5 LOC)netlify/functions/process-data.js
function toNullIfBlank(value){
if (value == null) return null;
const str = String(value).trim();
return str === "" ? null : str;
}coerceValue function · javascript · L183-L214 (32 LOC)netlify/functions/process-data.js
function coerceValue(value, type){
const raw = toNullIfBlank(value);
if (raw == null) return null;
if (type === "text") return String(raw);
if (type === "uuid") return String(raw);
if (type === "int"){
const n = Number(raw);
if (!Number.isFinite(n)) throw new Error(`Expected integer, got '${raw}'`);
return Math.trunc(n);
}
if (type === "float"){
const n = Number(raw);
if (!Number.isFinite(n)) throw new Error(`Expected number, got '${raw}'`);
return n;
}
if (type === "timestamptz"){
const d = new Date(raw);
if (Number.isNaN(d.getTime())) throw new Error(`Expected timestamp, got '${raw}'`);
return d.toISOString();
}
if (type === "json"){
if (typeof raw === "object") return raw;
try {
return JSON.parse(String(raw));
} catch {
return { raw: String(raw) };
}
}
return raw;
}normalizeRow function · javascript · L216-L282 (67 LOC)netlify/functions/process-data.js
function normalizeRow(row, rowNumber, mappedHeaders, schema, context){
const record = {};
const errors = [];
row.forEach((value, idx) => {
const column = mappedHeaders[idx];
if (!column) return;
const meta = schema.columns[column];
if (!meta) return;
try {
const coerced = coerceValue(value, meta.type);
if (coerced == null) return;
if (record[column] == null || record[column] === ""){
record[column] = coerced;
}
} catch (error){
errors.push(`column '${column}': ${error.message}`);
}
});
if (schema.columns.project_id && !record.project_id && context.projectId){
record.project_id = context.projectId;
}
if (schema.columns.created_by && !record.created_by && context.userId){
record.created_by = context.userId;
}
if (schema.columns.actor_user_id && !record.actor_user_id && context.userId){
record.actor_user_id = context.userId;
}
Object.entries(schema.defaults || {}).forEach(([key, value]) Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
isLikelyAuthError function · javascript · L284-L286 (3 LOC)netlify/functions/process-data.js
function isLikelyAuthError(message){
return /permission|rls|not authorized|forbidden|jwt|auth/i.test(String(message || ""));
}parseInput function · javascript · L288-L314 (27 LOC)netlify/functions/process-data.js
async function parseInput(event){
const contentType = event.headers["content-type"] || event.headers["Content-Type"] || "";
if (contentType.includes("multipart/form-data")){
return parseMultipart(event);
}
if (!event.body) return { fields: {}, file: null };
let body;
try {
body = event.isBase64Encoded
? JSON.parse(Buffer.from(event.body, "base64").toString("utf8"))
: JSON.parse(event.body);
} catch {
throw new Error("Invalid JSON body");
}
const rows = Array.isArray(body.rows) ? body.rows : [];
const headers = Array.isArray(body.headers) ? body.headers : [];
const gridRows = headers.length ? [headers, ...rows] : rows;
return {
fields: body,
file: null,
gridRows,
};
}handler function · javascript · L3-L84 (82 LOC)netlify/functions/translate.js
export async function handler(event){
if (event.httpMethod !== "POST"){
return {
statusCode: 405,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Method not allowed" }),
};
}
let payload = {};
try{
payload = JSON.parse(event.body || "{}");
} catch {
payload = {};
}
const text = String(payload.text || "").trim();
const targetLang = String(payload.target_lang || "").toLowerCase();
if (!text || !allowedTargets.has(targetLang)){
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Invalid text or target_lang" }),
};
}
const provider = String(process.env.TRANSLATE_PROVIDER || "libretranslate").toLowerCase();
if (provider !== "libretranslate"){
return {
statusCode: 500,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Unsupported translate provider" }),
};
}
coninfer_enclosure function · python · L19-L27 (9 LOC)scripts/export_sites_coords_template.py
def infer_enclosure(name: str) -> str:
text = clean_text(name)
if not text:
return ""
direct = re.match(r"^\d+(?:\/@[\w.]+)?$", text)
if direct:
return text
m = re.search(r"\b(\d+(?:\/@[\w.]+)?)\b", text)
return m.group(1) if m else textfetch_sites function · python · L30-L66 (37 LOC)scripts/export_sites_coords_template.py
def fetch_sites(
supabase_url: str,
supabase_key: str,
project_id: str | None,
limit: int,
) -> list[dict[str, Any]]:
base = supabase_url.rstrip("/")
endpoint = f"{base}/rest/v1/sites"
headers = {
"apikey": supabase_key,
"Authorization": f"Bearer {supabase_key}",
"Accept": "application/json",
}
select = "id,project_id,name,gps_lat,gps_lng,lat,lng,created_at"
params: dict[str, str] = {
"select": select,
"order": "created_at.asc",
"limit": str(limit),
}
if project_id:
params["project_id"] = f"eq.{project_id}"
query = urllib.parse.urlencode(params, safe=".,*()")
url = f"{endpoint}?{query}"
req = urllib.request.Request(url, headers=headers, method="GET")
try:
with urllib.request.urlopen(req, timeout=60) as resp:
body = resp.read().decode("utf-8", errors="replace")
status = getattr(resp, "status", 200)
except Exception as exc:
rrun function · python · L69-L117 (49 LOC)scripts/export_sites_coords_template.py
def run(
out_csv: Path,
supabase_url: str,
supabase_key: str,
project_id: str | None,
limit: int,
) -> None:
rows = fetch_sites(supabase_url, supabase_key, project_id, limit)
out_csv.parent.mkdir(parents=True, exist_ok=True)
headers = [
"external_ref",
"location_name",
"enclosure",
"latitude",
"longitude",
"job_map",
"project_id",
"site_id",
"site_name",
]
written = 0
with out_csv.open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=headers)
writer.writeheader()
for row in rows:
name = clean_text(row.get("name", ""))
enclosure = infer_enclosure(name)
lat = row.get("gps_lat")
lng = row.get("gps_lng")
if lat is None:
lat = row.get("lat")
if lng is None:
lng = row.get("lng")
writer.writerow(
main function · python · L120-L150 (31 LOC)scripts/export_sites_coords_template.py
def main() -> None:
parser = argparse.ArgumentParser(
description="Export current SpecCom sites into a coords CSV template for Wired production joins."
)
parser.add_argument("--out", required=True, help="Output CSV path.")
parser.add_argument("--project-id", default="", help="Optional project UUID filter.")
parser.add_argument("--limit", type=int, default=5000, help="Max sites to export.")
parser.add_argument(
"--supabase-url",
default=os.getenv("SUPABASE_URL", "").strip(),
help="Supabase project URL (or set SUPABASE_URL).",
)
parser.add_argument(
"--supabase-key",
default=(os.getenv("SUPABASE_SERVICE_ROLE_KEY", "") or os.getenv("SUPABASE_ANON_KEY", "")).strip(),
help="Supabase API key (prefer service role) or set SUPABASE_SERVICE_ROLE_KEY.",
)
args = parser.parse_args()
if not args.supabase_url:
raise SystemExit("Missing --supabase-url (or SUPABASE_URL env).")
if not args.ssanitize_slug function · python · L21-L23 (3 LOC)scripts/import_proof_packets.py
def sanitize_slug(text: str) -> str:
slug = re.sub(r"[^a-z0-9]+", "_", text.lower()).strip("_")
return slug or "unknown"Open data scored by Repobility · https://repobility.com
parse_source_name function · python · L26-L34 (9 LOC)scripts/import_proof_packets.py
def parse_source_name(pdf_name: str) -> tuple[str, str | None, int | None]:
stem = Path(pdf_name).stem
match = re.match(r"^\s*([A-Za-z]{1,4})\s+(.+?)\s*(?:\((\d+)\))?\s*$", stem)
if not match:
return stem.strip(), None, None
code = match.group(1).strip().upper()
location = match.group(2).strip()
reported = int(match.group(3)) if match.group(3) else None
return location, code, reportedgps_to_decimal function · python · L41-L63 (23 LOC)scripts/import_proof_packets.py
def gps_to_decimal(gps_info: dict[int, Any]) -> tuple[float | None, float | None]:
def rational_to_float(value: Any) -> float:
if isinstance(value, tuple) and len(value) == 2:
return float(value[0]) / float(value[1]) if value[1] else 0.0
if hasattr(value, "numerator") and hasattr(value, "denominator"):
return float(value.numerator) / float(value.denominator) if value.denominator else 0.0
return float(value)
def dms_to_decimal(values: Any, ref: str | bytes | None) -> float | None:
if not values or len(values) < 3:
return None
degrees = rational_to_float(values[0])
minutes = rational_to_float(values[1])
seconds = rational_to_float(values[2])
decimal = degrees + (minutes / 60.0) + (seconds / 3600.0)
ref_text = ref.decode() if isinstance(ref, bytes) else str(ref or "")
if ref_text.upper() in {"S", "W"}:
decimal *= -1
return decimal
lat = dms_PhotoRecord class · python · L67-L76 (10 LOC)scripts/import_proof_packets.py
class PhotoRecord:
file_name: str
relative_path: str
sha1: str
size_bytes: int
width: int | None
height: int | None
captured_at: str | None
gps_lat: float | None
gps_lng: float | Nonepage 1 / 3next ›