Nicholai 16cee69250 __Admin dashboard scaffolded with D1 database and R2 file uploads__
This commit implements the core admin dashboard functionality including NextAuth authentication, Cloudflare D1 database integration with complete schema, and Cloudflare R2 file upload system for portfolio images. Features include artist management, appointment scheduling, and data migration capabilities.
2025-09-17 16:08:34 -06:00

1 line
7.4 KiB
JavaScript

"use strict";(()=>{var e={};e.id=5998,e.ids=[5998],e.modules={72934:e=>{e.exports=require("next/dist/client/components/action-async-storage.external.js")},54580:e=>{e.exports=require("next/dist/client/components/request-async-storage.external.js")},45869:e=>{e.exports=require("next/dist/client/components/static-generation-async-storage.external.js")},20399:e=>{e.exports=require("next/dist/compiled/next-server/app-page.runtime.prod.js")},30517:e=>{e.exports=require("next/dist/compiled/next-server/app-route.runtime.prod.js")},27790:e=>{e.exports=require("assert")},78893:e=>{e.exports=require("buffer")},84770:e=>{e.exports=require("crypto")},17702:e=>{e.exports=require("events")},32615:e=>{e.exports=require("http")},35240:e=>{e.exports=require("https")},86624:e=>{e.exports=require("querystring")},17360:e=>{e.exports=require("url")},21764:e=>{e.exports=require("util")},71568:e=>{e.exports=require("zlib")},27588:(e,t,r)=>{r.r(t),r.d(t,{originalPathname:()=>w,patchFetch:()=>j,requestAsyncStorage:()=>x,routeModule:()=>m,serverHooks:()=>v,staticGenerationAsyncStorage:()=>h});var a={};r.r(a),r.d(a,{DELETE:()=>y,GET:()=>g,POST:()=>f,dynamic:()=>d});var n=r(73278),o=r(45002),s=r(54877),i=r(71309),u=r(18445),l=r(33897),p=r(69518),c=r(1035);let d="force-dynamic";async function f(e,{params:t}={},r){try{let t=await (0,u.getServerSession)(l.Lz);if(!t?.user)return i.NextResponse.json({error:"Unauthorized"},{status:401});let a=await e.formData(),n=a.get("file"),o=a.get("key"),s=a.get("artistId"),d=a.get("caption"),f=a.get("tags");if(!n)return i.NextResponse.json({error:"No file provided"},{status:400});let y=(0,p.Jw)(n,{maxSize:10485760,allowedTypes:["image/jpeg","image/png","image/webp","image/gif"]},r?.env);if(!y.valid)return i.NextResponse.json({error:y.error},{status:400});let g=await (0,p.fo)(n,o,{contentType:n.type,metadata:{uploadedBy:t.user.id,uploadedAt:new Date().toISOString(),originalName:n.name,artistId:s||"",caption:d||"",tags:f||""}},r?.env);if(!g.success)return i.NextResponse.json({error:g.error||"Upload failed"},{status:500});if(s&&g.url)try{let e=f?JSON.parse(f):[];await (0,c.xd)(s,{url:g.url,caption:d||void 0,tags:e,orderIndex:0,isPublic:!0},r?.env)}catch(e){console.error("Failed to save portfolio image to database:",e)}return i.NextResponse.json({success:!0,url:g.url,key:g.key,filename:n.name,size:n.size,type:n.type})}catch(e){return console.error("Upload error:",e),i.NextResponse.json({error:"Upload failed"},{status:500})}}async function y(e,{params:t}={},a){try{let t=await (0,u.getServerSession)(l.Lz);if(!t?.user)return i.NextResponse.json({error:"Unauthorized"},{status:401});let{searchParams:n}=new URL(e.url),o=n.get("key");if(!o)return i.NextResponse.json({error:"File key is required"},{status:400});let{deleteFromR2:s}=await Promise.resolve().then(r.bind(r,69518));if(!await s(o,a?.env))return i.NextResponse.json({error:"Failed to delete file"},{status:500});return i.NextResponse.json({success:!0,message:"File deleted successfully"})}catch(e){return console.error("Delete error:",e),i.NextResponse.json({error:"Delete failed"},{status:500})}}async function g(e,{params:t}={},r){try{let e=await (0,u.getServerSession)(l.Lz);if(!e?.user)return i.NextResponse.json({error:"Unauthorized"},{status:401});return i.NextResponse.json({error:"Presigned URLs not implemented yet. Use direct upload via POST."},{status:501})}catch(e){return console.error("Presigned URL error:",e),i.NextResponse.json({error:"Failed to generate presigned URL"},{status:500})}}let m=new n.AppRouteRouteModule({definition:{kind:o.x.APP_ROUTE,page:"/api/upload/route",pathname:"/api/upload",filename:"route",bundlePath:"app/api/upload/route"},resolvedPagePath:"/home/Nicholai/Documents/Dev/united_v03/united-tattoo/united-tattoo/app/api/upload/route.ts",nextConfigOutput:"standalone",userland:a}),{requestAsyncStorage:x,staticGenerationAsyncStorage:h,serverHooks:v}=m,w="/api/upload/route";function j(){return(0,s.patchFetch)({serverHooks:v,staticGenerationAsyncStorage:h})}},69518:(e,t,r)=>{r.d(t,{Jw:()=>i,deleteFromR2:()=>s,fo:()=>o});var a=r(1035);class n{constructor(e){this.bucket=(0,a.Ms)(e),this.baseUrl=process.env.R2_PUBLIC_URL||""}async uploadFile(e,t,r){try{let a=e instanceof File?await e.arrayBuffer():e.buffer,n=r?.contentType||(e instanceof File?e.type:"application/octet-stream");await this.bucket.put(t,a,{httpMetadata:{contentType:n},customMetadata:r?.metadata||{}});let o=`${this.baseUrl}/${t}`;return{success:!0,url:o,key:t}}catch(e){return console.error("R2 upload error:",e),{success:!1,error:e instanceof Error?e.message:"Upload failed"}}}async bulkUpload(e,t="uploads"){let r=[],a=[];for(let n of e)try{let e=`${t}/${Date.now()}-${n.name}`,o=await this.uploadFile(n,e,{contentType:n.type,metadata:{originalName:n.name,uploadedAt:new Date().toISOString()}});o.success&&o.url&&o.key?r.push({filename:n.name,url:o.url,key:o.key,size:n.size,mimeType:n.type}):a.push({filename:n.name,error:o.error||"Upload failed"})}catch(e){a.push({filename:n.name,error:e instanceof Error?e.message:"Upload failed"})}return{successful:r,failed:a,total:e.length}}async deleteFile(e){try{return await this.bucket.delete(e),!0}catch(e){return console.error("R2 delete error:",e),!1}}async getFileMetadata(e){try{return await this.bucket.get(e)}catch(e){return console.error("R2 metadata error:",e),null}}async generatePresignedUrl(e,t=3600){try{return null}catch(e){return console.error("Presigned URL error:",e),null}}validateFile(e,t){let r=t?.maxSize||10485760,a=t?.allowedTypes||["image/jpeg","image/png","image/webp","image/gif"];return e.size>r?{valid:!1,error:`File size exceeds ${Math.round(r/1024/1024)}MB limit`}:a.includes(e.type)?{valid:!0}:{valid:!1,error:`File type ${e.type} not allowed`}}generateFileKey(e,t="uploads"){let r=Date.now(),a=Math.random().toString(36).substring(2,15),n=e.split(".").pop(),o=e.replace(/\.[^/.]+$/,"").replace(/[^a-zA-Z0-9]/g,"-");return`${t}/${r}-${a}-${o}.${n}`}}async function o(e,t,r,a){let o=new n(a),s=t||o.generateFileKey(e.name);return await o.uploadFile(e,s,r)}async function s(e,t){let r=new n(t);return await r.deleteFile(e)}function i(e,t,r){return new n(r).validateFile(e,t)}},32482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0})},18445:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0});var a={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o.default}});var n=r(32482);Object.keys(n).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(a,e))&&(e in t&&t[e]===n[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return n[e]}}))});var o=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=s(void 0);if(r&&r.has(e))return r.get(e);var a={__proto__:null},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&({}).hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(a,o,i):a[o]=e[o]}return a.default=e,r&&r.set(e,a),a}(r(4128));function s(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(s=function(e){return e?r:t})(e)}Object.keys(o).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(a,e))&&(e in t&&t[e]===o[e]||Object.defineProperty(t,e,{enumerable:!0,get:function(){return o[e]}}))})}};var t=require("../../../webpack-runtime.js");t.C(e);var r=e=>t(t.s=e),a=t.X(0,[9379,8213,4128,4833,1253],()=>r(27588));module.exports=a})();