feat: add admin panel, Openinary media integration and standardized footer backlink
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import bcrypt from 'bcryptjs'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
async function main() {
|
||||
const password = await bcrypt.hash('admin123', 10)
|
||||
const user = await prisma.user.upsert({
|
||||
where: { username: 'admin' },
|
||||
update: { password }, // update password if already exists
|
||||
create: {
|
||||
username: 'admin',
|
||||
password,
|
||||
},
|
||||
})
|
||||
console.log('Admin user created:', user.username)
|
||||
}
|
||||
|
||||
main()
|
||||
.then(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
.catch(async (e) => {
|
||||
console.error(e)
|
||||
await prisma.$disconnect()
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,47 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config({ path: '.env.local' });
|
||||
|
||||
async function uploadFile(filePath, folderName) {
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const mimeTypes = {
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.webp': 'image/webp'
|
||||
};
|
||||
const mimeType = mimeTypes[ext] || 'application/octet-stream';
|
||||
|
||||
const blob = new Blob([fileBuffer], { type: mimeType });
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('files', blob, path.basename(filePath));
|
||||
formData.append('folder', folderName);
|
||||
|
||||
console.log(`Uploading ${filePath} to folder ${folderName}...`);
|
||||
|
||||
try {
|
||||
const res = await fetch(`${process.env.OPENINARY_API_URL}/api/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.OPENINARY_API_KEY}`
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text();
|
||||
console.error(`Error uploading ${filePath}:`, errorText);
|
||||
} else {
|
||||
const data = await res.json();
|
||||
console.log(`Success: ${data.files[0].url}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Exception uploading ${filePath}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
uploadFile(path.join(process.cwd(), 'public', 'logo.png'), 'moygrup').then(() => console.log('Done'));
|
||||
@@ -0,0 +1,67 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config({ path: '.env.local' });
|
||||
|
||||
async function uploadFile(filePath, folderName) {
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const mimeTypes = {
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.webp': 'image/webp'
|
||||
};
|
||||
const mimeType = mimeTypes[ext] || 'application/octet-stream';
|
||||
|
||||
const blob = new Blob([fileBuffer], { type: mimeType });
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('files', blob, path.basename(filePath));
|
||||
formData.append('folder', folderName);
|
||||
|
||||
console.log(`Uploading ${filePath} to folder ${folderName}...`);
|
||||
|
||||
try {
|
||||
const res = await fetch(`${process.env.OPENINARY_API_URL}/api/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.OPENINARY_API_KEY}`
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const errorText = await res.text();
|
||||
console.error(`Error uploading ${filePath}:`, errorText);
|
||||
} else {
|
||||
const data = await res.json();
|
||||
console.log(`Success: ${data.files[0].url}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Exception uploading ${filePath}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function scanAndUpload(dir, baseFolder) {
|
||||
const items = fs.readdirSync(dir);
|
||||
for (const item of items) {
|
||||
// Skip svg files and some special files
|
||||
if (item.endsWith('.svg') || item === '.DS_Store' || item === 'logo.png') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const fullPath = path.join(dir, item);
|
||||
const stat = fs.statSync(fullPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
await scanAndUpload(fullPath, `${baseFolder}/${item}`);
|
||||
} else {
|
||||
await uploadFile(fullPath, baseFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PUBLIC_DIR = path.join(process.cwd(), 'public');
|
||||
scanAndUpload(PUBLIC_DIR, 'moygrup').then(() => console.log('Done'));
|
||||
Reference in New Issue
Block a user