Compare commits
57 Commits
nico/2-feb
...
staggingwe
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b59d6bf09 | |||
| b69df2454e | |||
| eb1ad54db6 | |||
| df198c320a | |||
| 21ec3ad1c1 | |||
| f550e29a75 | |||
| 3a115908c4 | |||
| bb7384f1e5 | |||
| 5ff791642c | |||
| df154806f7 | |||
| b803c7a90c | |||
| 25000d0b0f | |||
| fb2fe67c23 | |||
| bbd52fb6f5 | |||
| 51460558d4 | |||
| 358ff14efe | |||
| d105ceeb6b | |||
| c865aee766 | |||
| 273dfdfd09 | |||
| 1d1d8e50dc | |||
| 092afe67d2 | |||
| 2d9170705d | |||
| fdf9a951a4 | |||
| ca74029688 | |||
| 1a8fc1a670 | |||
| 19235f0791 | |||
| 61de7d8d33 | |||
| 8fb85ce56c | |||
| 1f98b6993d | |||
| f3a10d63d1 | |||
| 7a42bec63b | |||
| 44c421129e | |||
| ddff427926 | |||
| 00c8caade4 | |||
| 0209f49449 | |||
| 344c6ada6d | |||
| 11acd04419 | |||
| 8d49213b68 | |||
| 96911e3cf1 | |||
| 9950c28b9b | |||
| fa0f3538d1 | |||
| 2778f53aff | |||
| 37ac91d4f4 | |||
| 217f4a9a3b | |||
| 5d6a7437ed | |||
| 752a6cabee | |||
| 134ddc6154 | |||
| 28979c6b49 | |||
| b2066caa13 | |||
| 023c77d636 | |||
| 9bf3ec72cf | |||
| f359f5b1ce | |||
| 1c1e8fb190 | |||
| 54f83da3b8 | |||
| f8985c550f | |||
| e3d909e760 | |||
| 16a8df50c1 |
219
QWEN.md
219
QWEN.md
@@ -1,219 +0,0 @@
|
||||
# Desa Darmasaba - Village Management System
|
||||
|
||||
## Project Overview
|
||||
|
||||
Desa Darmasaba is a comprehensive Next.js 15 application designed for village management services in Badung, Bali. The platform serves as a digital hub for government services, public information, news, and community engagement for the residents of Darmasaba village.
|
||||
|
||||
### Key Technologies
|
||||
- **Framework**: Next.js 15 with App Router
|
||||
- **Language**: TypeScript with strict mode
|
||||
- **Styling**: Mantine UI components with custom CSS
|
||||
- **Backend**: Elysia.js API server integrated with Next.js
|
||||
- **Database**: PostgreSQL with Prisma ORM
|
||||
- **State Management**: Jotai for global state
|
||||
- **Authentication**: JWT with iron-session
|
||||
- **Runtime**: Bun (instead of Node.js)
|
||||
|
||||
### Architecture
|
||||
The application follows a modern full-stack architecture with:
|
||||
- Frontend built with Next.js 15 and TypeScript
|
||||
- Backend API endpoints using Elysia.js
|
||||
- PostgreSQL database managed with Prisma ORM
|
||||
- Mantine UI library for consistent design components
|
||||
- File storage system for managing images and documents
|
||||
- Comprehensive user authentication and authorization system
|
||||
|
||||
## Features
|
||||
|
||||
The application provides extensive functionality across multiple domains:
|
||||
|
||||
### Government Services
|
||||
- Public service information and requests
|
||||
- Administrative online services
|
||||
- Community announcements and news
|
||||
- Village profile and governance information
|
||||
|
||||
### Health Services
|
||||
- Healthcare facility information
|
||||
- Health programs and initiatives
|
||||
- Emergency health contacts
|
||||
- Health articles and education
|
||||
- Posyandu (community health posts) information
|
||||
|
||||
### Economic Development
|
||||
- Local market information
|
||||
- Job listings and employment opportunities
|
||||
- Village economic statistics
|
||||
- Business registration and support
|
||||
|
||||
### Innovation & Technology
|
||||
- Digital village initiatives
|
||||
- Technology adoption programs
|
||||
- Innovation proposal system
|
||||
- Smart village features
|
||||
|
||||
### Education
|
||||
- School information and statistics
|
||||
- Scholarship programs
|
||||
- Educational support services
|
||||
- Library and learning resources
|
||||
|
||||
### Environmental Management
|
||||
- Waste management systems
|
||||
- Green initiatives
|
||||
- Environmental conservation programs
|
||||
- Community participation activities
|
||||
|
||||
### Security & Safety
|
||||
- Emergency contacts
|
||||
- Police station information
|
||||
- Crime prevention measures
|
||||
- Community safety programs
|
||||
|
||||
## Building and Running
|
||||
|
||||
### Prerequisites
|
||||
- Bun runtime (version specified in package.json)
|
||||
- PostgreSQL database
|
||||
- Environment variables configured
|
||||
|
||||
### Setup Commands
|
||||
```bash
|
||||
# Install dependencies
|
||||
bun install
|
||||
|
||||
# Set up environment variables
|
||||
cp .env.example .env.local
|
||||
# Edit .env.local with your configuration
|
||||
|
||||
# Database setup
|
||||
bunx prisma db push
|
||||
bunx prisma generate
|
||||
|
||||
# Seed database (optional)
|
||||
bun run prisma/seed.ts
|
||||
|
||||
# Development mode
|
||||
bun run dev
|
||||
|
||||
# Production build
|
||||
bun run build
|
||||
|
||||
# Start production server
|
||||
bun run start
|
||||
```
|
||||
|
||||
### Additional Commands
|
||||
```bash
|
||||
# Linting (ESLint)
|
||||
bunx eslint .
|
||||
|
||||
# Type checking
|
||||
bunx tsc --noEmit
|
||||
|
||||
# Prisma operations
|
||||
bunx prisma generate
|
||||
bunx prisma db push
|
||||
bunx prisma studio
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── app/ # Next.js app router pages
|
||||
│ ├── _com/ # Common components
|
||||
│ ├── admin/ # Admin panel routes
|
||||
│ ├── api/ # API routes
|
||||
│ ├── darmasaba/ # Main application pages
|
||||
│ ├── login/ # Authentication pages
|
||||
│ └── ... # Other feature pages
|
||||
├── con/ # Constants and static data
|
||||
├── hooks/ # Custom React hooks
|
||||
├── lib/ # Utility functions and configurations
|
||||
├── middlewares/ # Middleware functions
|
||||
├── state/ # Global state management
|
||||
├── store/ # Additional state management
|
||||
├── types/ # TypeScript type definitions
|
||||
├── utils/ # Utility functions
|
||||
├── middleware.ts # Application middleware
|
||||
└── schema.ts # Schema definitions
|
||||
```
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Code Style
|
||||
- Use absolute imports with `@/` alias (configured in tsconfig.json)
|
||||
- Group imports: external libraries first, then internal modules
|
||||
- Follow consistent naming conventions:
|
||||
- Components: PascalCase (e.g., `UploadImage.tsx`)
|
||||
- Files: kebab-case for utilities (e.g., `api-fetch.ts`)
|
||||
- Variables/Functions: camelCase
|
||||
- Constants: UPPER_SNAKE_CASE
|
||||
|
||||
### TypeScript Configuration
|
||||
- Strict mode enabled (`"strict": true`)
|
||||
- Target: ES2017
|
||||
- Module resolution: bundler
|
||||
- Path alias: `@/*` maps to `./src/*`
|
||||
|
||||
### Error Handling
|
||||
- Use try-catch blocks for async operations
|
||||
- Implement proper error boundaries in React components
|
||||
- Log errors appropriately without exposing sensitive data
|
||||
- Use Zod for runtime validation and type safety
|
||||
|
||||
### Security Practices
|
||||
- Validate all user inputs with Zod schemas
|
||||
- Use JWT tokens for authentication
|
||||
- Implement proper CORS configuration
|
||||
- Never expose database credentials or API keys
|
||||
- Use HTTPS in production
|
||||
- Implement rate limiting for sensitive endpoints
|
||||
|
||||
### Performance Considerations
|
||||
- Use Next.js Image optimization
|
||||
- Implement proper caching strategies
|
||||
- Use React.memo for expensive components
|
||||
- Optimize bundle size with dynamic imports
|
||||
- Use Prisma query optimization
|
||||
|
||||
## Database Schema
|
||||
|
||||
The application uses a comprehensive PostgreSQL database schema with Prisma ORM, featuring:
|
||||
|
||||
- **User Management**: Complete user authentication system with roles and permissions
|
||||
- **Content Management**: News, announcements, and various content types
|
||||
- **Service Management**: Various government and community services
|
||||
- **File Storage**: Centralized file management system
|
||||
- **Health Information**: Healthcare facilities and programs
|
||||
- **Economic Data**: Market information and employment data
|
||||
- **Educational Resources**: Schools, scholarships, and educational programs
|
||||
- **Environmental Data**: Sustainability and environmental management
|
||||
- **Security Information**: Emergency contacts and safety measures
|
||||
|
||||
## API Structure
|
||||
|
||||
- Backend uses Elysia.js with TypeScript
|
||||
- API routes are in `src/app/api/[[...slugs]]/` directory
|
||||
- Use treaty client for type-safe API calls
|
||||
- Follow RESTful conventions for endpoints
|
||||
- Include proper HTTP status codes and error responses
|
||||
|
||||
## Deployment
|
||||
|
||||
The application includes deployment scripts for staging environments, with:
|
||||
- Automated builds using Bun
|
||||
- Database migration handling
|
||||
- Environment-specific configurations
|
||||
- PM2 process management for production
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The application uses a custom Elysia.js server integrated with Next.js API routes
|
||||
- Image uploads are handled through `/api/upl-img-single` endpoint
|
||||
- Database seeding is done with Bun runtime
|
||||
- The app supports Indonesian locale (id_ID) for SEO and content
|
||||
- CORS is configured to allow cross-origin requests during development
|
||||
- Authentication is implemented with JWT tokens and iron-session
|
||||
- The application has both public-facing and admin sections with different access controls
|
||||
@@ -50,6 +50,7 @@
|
||||
"add": "^2.0.6",
|
||||
"adm-zip": "^0.5.16",
|
||||
"animate.css": "^4.1.1",
|
||||
"async-mutex": "^0.5.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"bun": "^1.2.2",
|
||||
"chart.js": "^4.4.8",
|
||||
|
||||
@@ -4,6 +4,7 @@ import maskotDesa from "../../../data/desa/profile/maskot_desa.json";
|
||||
import profilePerbekel from "../../../data/desa/profile/profil_perbekel.json";
|
||||
import profileDesaImage from "../../../data/desa/profile/profileDesaImage.json";
|
||||
import sejarahDesa from "../../../data/desa/profile/sejarah_desa.json";
|
||||
import visiMisiDesa from "../../../data/desa/profile/visi_misi_desa.json";
|
||||
|
||||
export async function seedProfileDesa() {
|
||||
// =========== SEJARAH DESA ===========
|
||||
@@ -26,6 +27,26 @@ export async function seedProfileDesa() {
|
||||
|
||||
console.log("sejarah desa success ...");
|
||||
|
||||
// =========== VISI MISI DESA ===========
|
||||
for (const l of visiMisiDesa) {
|
||||
await prisma.visiMisiDesa.upsert({
|
||||
where: {
|
||||
id: l.id,
|
||||
},
|
||||
update: {
|
||||
visi: l.visi,
|
||||
misi: l.misi,
|
||||
},
|
||||
create: {
|
||||
id: l.id,
|
||||
visi: l.visi,
|
||||
misi: l.misi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("visi misi desa success ...");
|
||||
|
||||
// =========== MASKOT DESA ===========
|
||||
for (const l of maskotDesa) {
|
||||
await prisma.maskotDesa.upsert({
|
||||
|
||||
@@ -4,6 +4,23 @@ import desaDigital from "../../data/inovasi/desa-digital/desa-digital.json";
|
||||
export async function seedDesaDigital() {
|
||||
console.log("🔄 Seeding Desa Digital...");
|
||||
for (const d of desaDigital) {
|
||||
let imageId: string | null = null;
|
||||
|
||||
if (d.imageName) {
|
||||
const image = await prisma.fileStorage.findUnique({
|
||||
where: { name: d.imageName },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!image) {
|
||||
console.warn(
|
||||
`⚠️ Image not found for desa digital "${d.name}": ${d.imageName}`,
|
||||
);
|
||||
} else {
|
||||
imageId = image.id;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.desaDigital.upsert({
|
||||
where: {
|
||||
id: d.id,
|
||||
@@ -11,13 +28,13 @@ export async function seedDesaDigital() {
|
||||
update: {
|
||||
name: d.name,
|
||||
deskripsi: d.deskripsi,
|
||||
imageId: d.imageId,
|
||||
imageId: imageId,
|
||||
},
|
||||
create: {
|
||||
id: d.id,
|
||||
name: d.name,
|
||||
deskripsi: d.deskripsi,
|
||||
imageId: d.imageId,
|
||||
imageId: imageId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,6 +63,23 @@ export async function seedLayananOnlineDesa() {
|
||||
console.log("✅ Jenis Pengaduan Masyarakat seeded successfully");
|
||||
console.log("🔄 Seeding Pengaduan Masyarakat...");
|
||||
for (const d of pengaduanMasyarakat) {
|
||||
let imageId: string | null = null;
|
||||
|
||||
if (d.imageName) {
|
||||
const image = await prisma.fileStorage.findUnique({
|
||||
where: { name: d.imageName },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!image) {
|
||||
console.warn(
|
||||
`⚠️ Image not found for pengaduan masyarakat "${d.name}": ${d.imageName}`,
|
||||
);
|
||||
} else {
|
||||
imageId = image.id;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.pengaduanMasyarakat.upsert({
|
||||
where: {
|
||||
id: d.id,
|
||||
@@ -74,7 +91,7 @@ export async function seedLayananOnlineDesa() {
|
||||
nomorTelepon: d.nomorTelepon,
|
||||
judulPengaduan: d.judulPengaduan,
|
||||
lokasiKejadian: d.lokasiKejadian,
|
||||
imageId: d.imageId,
|
||||
imageId: imageId,
|
||||
deskripsiPengaduan: d.deskripsiPengaduan,
|
||||
jenisPengaduanId: d.jenisPengaduanId,
|
||||
},
|
||||
@@ -86,7 +103,7 @@ export async function seedLayananOnlineDesa() {
|
||||
nomorTelepon: d.nomorTelepon,
|
||||
judulPengaduan: d.judulPengaduan,
|
||||
lokasiKejadian: d.lokasiKejadian,
|
||||
imageId: d.imageId,
|
||||
imageId: imageId,
|
||||
deskripsiPengaduan: d.deskripsiPengaduan,
|
||||
jenisPengaduanId: d.jenisPengaduanId,
|
||||
},
|
||||
|
||||
71
prisma/_seeder_list/lingkungan/seed_data_gotong_royong.ts
Normal file
71
prisma/_seeder_list/lingkungan/seed_data_gotong_royong.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import kategoriGotongRoyong from "../../data/lingkungan/gotong-royong/kategori-gotong-royong.json";
|
||||
import gotongRoyong from "../../data/lingkungan/gotong-royong/gotong-royong.json";
|
||||
|
||||
export async function seedDataGotongRoyong() {
|
||||
console.log("🔄 Seeding Kategori Gotong Royong...");
|
||||
|
||||
for (const k of kategoriGotongRoyong) {
|
||||
await prisma.kategoriKegiatan.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
nama: k.nama,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
nama: k.nama,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Kategori Gotong Royong seeded successfully");
|
||||
|
||||
console.log("🔄 Seeding Gotong Royong...");
|
||||
for (const k of gotongRoyong) {
|
||||
let imageId: string | null = null;
|
||||
|
||||
if (k.imageName) {
|
||||
const image = await prisma.fileStorage.findUnique({
|
||||
where: { name: k.imageName },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!image) {
|
||||
console.warn(
|
||||
`⚠️ Image not found for gotong royong "${k.judul}": ${k.imageName}`,
|
||||
);
|
||||
} else {
|
||||
imageId = image.id;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.kegiatanDesa.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
judul: k.judul,
|
||||
deskripsiSingkat: k.deskripsiSingkat,
|
||||
deskripsiLengkap: k.deskripsiLengkap,
|
||||
tanggal: k.tanggal,
|
||||
lokasi: k.lokasi,
|
||||
partisipan: k.partisipan,
|
||||
imageId: imageId,
|
||||
kategoriKegiatanId: k.kategoriKegiatanId,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
judul: k.judul,
|
||||
deskripsiSingkat: k.deskripsiSingkat,
|
||||
deskripsiLengkap: k.deskripsiLengkap,
|
||||
tanggal: k.tanggal,
|
||||
lokasi: k.lokasi,
|
||||
partisipan: k.partisipan,
|
||||
imageId: imageId,
|
||||
kategoriKegiatanId: k.kategoriKegiatanId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Gotong Royong seeded successfully");
|
||||
}
|
||||
27
prisma/_seeder_list/lingkungan/seed_data_lingkungan_desa.ts
Normal file
27
prisma/_seeder_list/lingkungan/seed_data_lingkungan_desa.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import dataLingkunganDesa from "../../data/lingkungan/data-lingkungan-desa/data-lingkungan-desa.json";
|
||||
|
||||
export async function seedDataLingkunganDesa() {
|
||||
console.log("🔄 Seeding Data Lingkungan Desa...");
|
||||
for (const p of dataLingkunganDesa) {
|
||||
await prisma.dataLingkunganDesa.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
name: p.name,
|
||||
jumlah: p.jumlah,
|
||||
deskripsi: p.deskripsi,
|
||||
icon: p.icon,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
jumlah: p.jumlah,
|
||||
deskripsi: p.deskripsi,
|
||||
icon: p.icon,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Data Lingkungan Desa seeded successfully");
|
||||
}
|
||||
63
prisma/_seeder_list/lingkungan/seed_edukasi_lingkungan.ts
Normal file
63
prisma/_seeder_list/lingkungan/seed_edukasi_lingkungan.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import tujuanEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/tujuan-edukasi-lingkungan.json";
|
||||
import materiEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/materi-edukasi-yang-diberikan.json";
|
||||
import contohEdukasiLingkungan from "../../data/lingkungan/edukasi-lingkungan/contoh-kegiatan-di-desa-darmasaba.json";
|
||||
|
||||
export async function seedEdukasiLingkungan() {
|
||||
for (const e of tujuanEdukasiLingkungan) {
|
||||
await prisma.tujuanEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: e.id,
|
||||
},
|
||||
update: {
|
||||
judul: e.judul,
|
||||
deskripsi: e.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: e.id,
|
||||
judul: e.judul,
|
||||
deskripsi: e.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("tujuan edukasi lingkungan success ...");
|
||||
|
||||
for (const m of materiEdukasiLingkungan) {
|
||||
await prisma.materiEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: m.id,
|
||||
},
|
||||
update: {
|
||||
judul: m.judul,
|
||||
deskripsi: m.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: m.id,
|
||||
judul: m.judul,
|
||||
deskripsi: m.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("materi edukasi lingkungan success ...");
|
||||
|
||||
for (const c of contohEdukasiLingkungan) {
|
||||
await prisma.contohEdukasiLingkungan.upsert({
|
||||
where: {
|
||||
id: c.id,
|
||||
},
|
||||
update: {
|
||||
judul: c.judul,
|
||||
deskripsi: c.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: c.id,
|
||||
judul: c.judul,
|
||||
deskripsi: c.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("contoh edukasi lingkungan success ...");
|
||||
}
|
||||
63
prisma/_seeder_list/lingkungan/seed_konservasi_adat_bali.ts
Normal file
63
prisma/_seeder_list/lingkungan/seed_konservasi_adat_bali.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import filosofiTriHita from "../../data/lingkungan/konservasi-adat-bali/filosofi-tri-hita.json";
|
||||
import bentukKonservasiBerdasarkanAdat from "../../data/lingkungan/konservasi-adat-bali/bentuk-konservasi.json";
|
||||
import nilaiKonservasiAdat from "../../data/lingkungan/konservasi-adat-bali/nilai-konservasi-adat.json";
|
||||
|
||||
export async function seedKonservasiAdatBali() {
|
||||
for (const f of filosofiTriHita) {
|
||||
await prisma.filosofiTriHita.upsert({
|
||||
where: {
|
||||
id: f.id,
|
||||
},
|
||||
update: {
|
||||
judul: f.judul,
|
||||
deskripsi: f.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: f.id,
|
||||
judul: f.judul,
|
||||
deskripsi: f.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("filosofi tri hita success ...");
|
||||
|
||||
for (const b of bentukKonservasiBerdasarkanAdat) {
|
||||
await prisma.bentukKonservasiBerdasarkanAdat.upsert({
|
||||
where: {
|
||||
id: b.id,
|
||||
},
|
||||
update: {
|
||||
judul: b.judul,
|
||||
deskripsi: b.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: b.id,
|
||||
judul: b.judul,
|
||||
deskripsi: b.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("bentuk konservasi berdasarkan adat success ...");
|
||||
|
||||
for (const n of nilaiKonservasiAdat) {
|
||||
await prisma.nilaiKonservasiAdat.upsert({
|
||||
where: {
|
||||
id: n.id,
|
||||
},
|
||||
update: {
|
||||
judul: n.judul,
|
||||
deskripsi: n.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: n.id,
|
||||
judul: n.judul,
|
||||
deskripsi: n.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log("nilai konservasi adat success ...");
|
||||
}
|
||||
51
prisma/_seeder_list/lingkungan/seed_pengelolaan_sampah.ts
Normal file
51
prisma/_seeder_list/lingkungan/seed_pengelolaan_sampah.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import pengelolaanSampah from "../../data/lingkungan/pengelolaan-sampah/pengelolaan-sampah.json";
|
||||
import keteranganBankSampah from "../../data/lingkungan/pengelolaan-sampah/keterangan-bank-sampah.json";
|
||||
|
||||
export async function seedPengelolaanSampah() {
|
||||
console.log("🔄 Seeding Pengelolaan Sampah...");
|
||||
for (const p of pengelolaanSampah) {
|
||||
await prisma.pengelolaanSampah.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
name: p.name,
|
||||
icon: p.icon,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
icon: p.icon,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Pengelolaan Sampah seeded successfully");
|
||||
|
||||
console.log("🔄 Seeding Keterangan Bank Sampah...");
|
||||
for (const p of keteranganBankSampah) {
|
||||
await prisma.keteranganBankSampahTerdekat.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
name: p.name,
|
||||
alamat: p.alamat,
|
||||
namaTempatMaps: p.namaTempatMaps,
|
||||
linkPetunjukArah: p.linkPetunjukArah,
|
||||
lat: p.lat,
|
||||
lng: p.lng,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
alamat: p.alamat,
|
||||
namaTempatMaps: p.namaTempatMaps,
|
||||
linkPetunjukArah: p.linkPetunjukArah,
|
||||
lat: p.lat,
|
||||
lng: p.lng,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Keterangan Bank Sampah seeded successfully");
|
||||
}
|
||||
27
prisma/_seeder_list/lingkungan/seed_program_penghijauan.ts
Normal file
27
prisma/_seeder_list/lingkungan/seed_program_penghijauan.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import programPenghijauan from "../../data/lingkungan/program-penghijauan/program-penghijauan.json";
|
||||
|
||||
export async function seedProgramPenghijauan() {
|
||||
console.log("🔄 Seeding Program Penghijauan...");
|
||||
for (const p of programPenghijauan) {
|
||||
await prisma.programPenghijauan.upsert({
|
||||
where: {
|
||||
id: p.id,
|
||||
},
|
||||
update: {
|
||||
name: p.name,
|
||||
judul: p.judul,
|
||||
deskripsi: p.deskripsi,
|
||||
icon: p.icon,
|
||||
},
|
||||
create: {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
judul: p.judul,
|
||||
deskripsi: p.deskripsi,
|
||||
icon: p.icon,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Program Penghijauan seeded successfully");
|
||||
}
|
||||
60
prisma/_seeder_list/pendidikan/seed_bimbingan_belajar.ts
Normal file
60
prisma/_seeder_list/pendidikan/seed_bimbingan_belajar.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import tujuanBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/tujuan-bimbingan-belajar-desa.json";
|
||||
import lokasiJadwalBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/lokasi-dan-jadwal.json";
|
||||
import fasilitasBimbinganBelajarDesa from "../../data/pendidikan/bimbingan-belajar-desa/fasilitas-yang-disediakan.json";
|
||||
|
||||
export async function seedBimbinganBelajar() {
|
||||
for (const t of tujuanBimbinganBelajarDesa) {
|
||||
await prisma.tujuanBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ tujuan bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
|
||||
for (const t of lokasiJadwalBimbinganBelajarDesa) {
|
||||
await prisma.lokasiJadwalBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
|
||||
for (const t of fasilitasBimbinganBelajarDesa) {
|
||||
await prisma.fasilitasBimbinganBelajarDesa.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
}
|
||||
23
prisma/_seeder_list/pendidikan/seed_data_pendidikan.ts
Normal file
23
prisma/_seeder_list/pendidikan/seed_data_pendidikan.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import dataPendidikan from "../../data/pendidikan/data-pendidikan/data-pendidikan.json";
|
||||
|
||||
export async function seedDataPendidikan() {
|
||||
console.log("🔄 Seeding Data pendidikan...");
|
||||
for (const k of dataPendidikan) {
|
||||
await prisma.dataPendidikan.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
name: k.name,
|
||||
jumlah: k.jumlah,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
name: k.name,
|
||||
jumlah: k.jumlah,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Data pendidikan seeded successfully");
|
||||
}
|
||||
71
prisma/_seeder_list/pendidikan/seed_data_perpustakaan.ts
Normal file
71
prisma/_seeder_list/pendidikan/seed_data_perpustakaan.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import dataPerpustakaan from "../../data/pendidikan/perpustakaan-digital/perpustakaan-digital.json";
|
||||
import kategoriBuku from "../../data/pendidikan/perpustakaan-digital/kategori-buku.json";
|
||||
|
||||
export async function seedDataPerpustakaan() {
|
||||
console.log("🔄 Seeding Kategori Buku...");
|
||||
for (const k of kategoriBuku) {
|
||||
await prisma.kategoriBuku.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
name: k.name,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
name: k.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Kategori Buku seeded successfully");
|
||||
|
||||
console.log("🔄 Seeding Data perpustakaan...");
|
||||
for (const k of dataPerpustakaan) {
|
||||
let imageId: string | null = null;
|
||||
|
||||
if (k.imageName) {
|
||||
const image = await prisma.fileStorage.findUnique({
|
||||
where: { name: k.imageName },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!image) {
|
||||
console.warn(
|
||||
`⚠️ Image not found for perpustakaan "${k.judul}": ${k.imageName}`,
|
||||
);
|
||||
} else {
|
||||
imageId = image.id;
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.dataPerpustakaan.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
judul: k.judul,
|
||||
deskripsi: k.deskripsi,
|
||||
kategoriId: k.kategoriId,
|
||||
imageId: imageId
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
judul: k.judul,
|
||||
deskripsi: k.deskripsi,
|
||||
kategoriId: k.kategoriId,
|
||||
imageId: imageId
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Data perpustakaan seeded successfully");
|
||||
}
|
||||
if (import.meta.main) {
|
||||
seedDataPerpustakaan()
|
||||
.then(() => {
|
||||
console.log("seed data perpustakaan success");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("gagal seed data perpustakaan", JSON.stringify(err));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import tujuanProgram from "../../data/pendidikan/program-pendidikan-anak/tujuan-program.json";
|
||||
import programUnggulan from "../../data/pendidikan/program-pendidikan-anak/program-unggulan.json";
|
||||
|
||||
export async function seedInfoProgramPendidikan() {
|
||||
for (const t of tujuanProgram) {
|
||||
await prisma.tujuanProgram.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ tujuan program seeded (editable later via UI)");
|
||||
for (const t of programUnggulan) {
|
||||
await prisma.programUnggulan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ program unggulan seeded (editable later via UI)");
|
||||
}
|
||||
74
prisma/_seeder_list/pendidikan/seed_info_sekolah.ts
Normal file
74
prisma/_seeder_list/pendidikan/seed_info_sekolah.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import jenjangPendidikan from "../../data/pendidikan/info-sekolah/jenjang-pendidikan.json";
|
||||
import lembagaPendidikan from "../../data/pendidikan/info-sekolah/lembaga.json";
|
||||
import siswa from "../../data/pendidikan/info-sekolah/siswa.json";
|
||||
import pengajar from "../../data/pendidikan/info-sekolah/pengajar.json";
|
||||
|
||||
export async function seedInfoSekolah() {
|
||||
for (const j of jenjangPendidikan) {
|
||||
await prisma.jenjangPendidikan.upsert({
|
||||
where: {
|
||||
id: j.id,
|
||||
},
|
||||
update: {
|
||||
nama: j.nama,
|
||||
},
|
||||
create: {
|
||||
id: j.id,
|
||||
nama: j.nama,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Jenjang Pendidikan seeded successfully");
|
||||
for (const j of lembagaPendidikan) {
|
||||
await prisma.lembaga.upsert({
|
||||
where: {
|
||||
id: j.id,
|
||||
},
|
||||
update: {
|
||||
nama: j.nama,
|
||||
jenjangId: j.jenjangId,
|
||||
},
|
||||
create: {
|
||||
id: j.id,
|
||||
nama: j.nama,
|
||||
jenjangId: j.jenjangId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Lembaga Pendidikan seeded successfully");
|
||||
for (const j of siswa) {
|
||||
await prisma.siswa.upsert({
|
||||
where: {
|
||||
id: j.id,
|
||||
},
|
||||
update: {
|
||||
nama: j.nama,
|
||||
lembagaId: j.lembagaId,
|
||||
},
|
||||
create: {
|
||||
id: j.id,
|
||||
nama: j.nama,
|
||||
lembagaId: j.lembagaId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ siswa seeded successfully");
|
||||
for (const j of pengajar) {
|
||||
await prisma.pengajar.upsert({
|
||||
where: {
|
||||
id: j.id,
|
||||
},
|
||||
update: {
|
||||
nama: j.nama,
|
||||
lembagaId: j.lembagaId,
|
||||
},
|
||||
create: {
|
||||
id: j.id,
|
||||
nama: j.nama,
|
||||
lembagaId: j.lembagaId,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ pengajar seeded successfully");
|
||||
}
|
||||
60
prisma/_seeder_list/pendidikan/seed_pendidikan_non_formal.ts
Normal file
60
prisma/_seeder_list/pendidikan/seed_pendidikan_non_formal.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import tujuanProgram from "../../data/pendidikan/pendidikan-non-formal/tujuan-program2.json";
|
||||
import tempatKegiatan from "../../data/pendidikan/pendidikan-non-formal/tempat-kegiatan.json";
|
||||
import jenisProgramYangDiselenggarakan from "../../data/pendidikan/pendidikan-non-formal/jenis-program-yang-diselenggarakan.json";
|
||||
|
||||
export async function seedPendidikanNonFormal() {
|
||||
for (const t of tujuanProgram) {
|
||||
await prisma.tujuanPendidikanNonFormal.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
|
||||
for (const t of tempatKegiatan) {
|
||||
await prisma.tempatKegiatan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
|
||||
for (const t of jenisProgramYangDiselenggarakan) {
|
||||
await prisma.jenisProgramYangDiselenggarakan.upsert({
|
||||
where: { id: t.id },
|
||||
update: {
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
create: {
|
||||
id: t.id,
|
||||
judul: t.judul,
|
||||
deskripsi: t.deskripsi,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log(
|
||||
"✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
);
|
||||
}
|
||||
@@ -3,30 +3,30 @@
|
||||
"id": "cmkkshcox000504l88lp54coc",
|
||||
"name": "Darmasaba Digital App",
|
||||
"deskripsi": "<p>Aplikasi digital desa yang dikembangkan oleh Pemerintah Desa Darmasaba pada tahun 2024 untuk mempermudah pelayanan publik dan informasi pemerintahan berbasis digital.</p>",
|
||||
"imageId": "cmkksb3jr0005vni4sp3ogr87"
|
||||
"imageName": "r_gBF0FuFpFPfSENHc4XI-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkkshln8000604l8c9b5b4il",
|
||||
"name": "D’DAMART (Darmasaba Digital Market)",
|
||||
"deskripsi": "<p>Sistem pasar UMKM digital berbasis website yang dikembangkan untuk meningkatkan akses pasar dan pemasaran produk UMKM Desa Darmasaba melalui platform digital.</p>",
|
||||
"imageId": "cmkksoze80008vni4ki2ry81r"
|
||||
"imageName": "uE2QwpbcXyBWxVYqCWQQT-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkm1a1g80007vnsw8ejmj816",
|
||||
"name": "Media Aspirasi dan Pengaduan Warga",
|
||||
"deskripsi": "<p>Media aspirasi dan pengaduan warga disediakan sebagai wadah partisipasi masyarakat dalam menyampaikan saran, masukan, maupun keluhan secara transparan dan terstruktur. Fitur ini memperkuat komunikasi dua arah antara pemerintah desa dan masyarakat, sehingga setiap aspirasi dapat ditindaklanjuti secara lebih cepat dan akuntabel.</p>",
|
||||
"imageId": "cmkm1a14d0005vnsww1tsd92o"
|
||||
"imageName": "c7xWNyoYp8Cak28NG5NoG-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkm0w0s50003vnswmwpnqsi5",
|
||||
"name": "Website Desa Resmi",
|
||||
"deskripsi": "<p>Website Desa Darmasaba berfungsi sebagai sarana utama penyampaian informasi resmi kepada masyarakat. Melalui website ini, pemerintah desa menghadirkan keterbukaan informasi publik, mempermudah akses warga terhadap berita, pengumuman, serta agenda kegiatan desa, sekaligus menjadi pusat data dan referensi terkait profil dan struktur pemerintahan desa.</p>",
|
||||
"imageId": "cmkm0z9hx0004vnswtjd2bk3z"
|
||||
"imageName": "kN09yF3sahmy-d5EaeGqA-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkm1c8wx000avnswksc56orq",
|
||||
"name": "Publikasi Kegiatan Desa Secara Digital",
|
||||
"deskripsi": "<p>Publikasi kegiatan desa secara digital bertujuan untuk mendokumentasikan dan menyebarluaskan berbagai aktivitas serta program kerja pemerintah desa. Melalui artikel dan dokumentasi foto, masyarakat dapat mengetahui perkembangan kegiatan desa secara terbuka, sekaligus meningkatkan kepercayaan publik terhadap pelaksanaan program desa.</p>",
|
||||
"imageId": "cmkm1c8py0008vnsw0unbxkpq"
|
||||
"imageName": "h_Gd0SoeIJVTi_5TWUO-P-mobile.webp"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"deskripsiPengaduan": "<p>Permintaan Pemasangan Spanduk Larangan Bagi Hewan</p>",
|
||||
"lokasiKejadian": "Banjar Darmasaba Tengah",
|
||||
"jenisPengaduanId": "eommt91ma000004lb4dpq7ll1",
|
||||
"imageId": "cmkkxep9l000evni4xkegbk72"
|
||||
"imageName": "gyNi4s8TnK2UrViU-gN2C-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkkrxmub0004vni41cwyhid5",
|
||||
@@ -21,7 +21,7 @@
|
||||
"deskripsiPengaduan": "<p>Laporan Anjing Liar Sering Menyerang Warga</p>",
|
||||
"lokasiKejadian": "Jl. Raya Darmasaba",
|
||||
"jenisPengaduanId": "eommt91ma000004lb4dpq8mm2",
|
||||
"imageId": "cmkkx9e38000bvni4azjd3u53"
|
||||
"imageName": "SQqSobKRg3ShvgPw_H41h-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkkrxmub0004vni41cwyhid6",
|
||||
@@ -33,6 +33,6 @@
|
||||
"deskripsiPengaduan": "<p>Pengelolaan Sampah Rumah Tangga Belum Efektif</p>",
|
||||
"lokasiKejadian": "Banjar Bucu",
|
||||
"jenisPengaduanId": "eommt91ma000004lb4dpq7ll1",
|
||||
"imageId": "cmkky60sq0000vnjjc55k84d2"
|
||||
"imageName": "y78xZ2axTOjz87gRKjVAf-mobile.webp"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"tanggal": "2024-01-28T00:00:00.000Z",
|
||||
"lokasi": "Pura Desa dan Pura Dalem, Desa Adat Tegal, Desa Darmasaba, Badung",
|
||||
"partisipan": 30,
|
||||
"imageId": "cmknb59md0000vnmam828iuzt",
|
||||
"imageName": "YgOX5qAP3O1PHG5XmQXkr-mobile.webp",
|
||||
"kategoriKegiatanId": "cmknan39v000004l8eiql149r"
|
||||
},
|
||||
{
|
||||
@@ -18,7 +18,7 @@
|
||||
"tanggal": "2023-11-17T00:00:00.000Z",
|
||||
"lokasi": "Desa Darmasaba, Badung",
|
||||
"partisipan": 25,
|
||||
"imageId": "cmknbp3vd0001vnmarjz542o7",
|
||||
"imageName": "qxqSDHe-akIRi1EkQFUbG-mobile.webp",
|
||||
"kategoriKegiatanId": "cmknan39v000004l8eiql149r"
|
||||
},
|
||||
{
|
||||
@@ -29,7 +29,7 @@
|
||||
"tanggal": "2022-05-26T00:00:00.000Z",
|
||||
"lokasi": "Pura Dalem Kangin, Desa Adat Tegal, Desa Darmasaba, Badung",
|
||||
"partisipan": 28,
|
||||
"imageId": "cmknbrj4r0002vnmantw9rn0l",
|
||||
"imageName": "iHTVkQZ1VdkMOXLt5qdAd-mobile.webp",
|
||||
"kategoriKegiatanId": "cmknan39v000004l8eiql149r"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -4,139 +4,195 @@
|
||||
"judul": "Laskar Pelangi",
|
||||
"deskripsi": "<p>Novel inspiratif tentang perjuangan anak-anak di Belitung dalam meraih pendidikan dan mimpi mereka</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq76bdzu",
|
||||
"imageId": "cmkqhbhxi0000vneamj3din9u"
|
||||
"imageName": "RnAdv7O0QAFrxkFLAXJSa-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqhedff0005vneas3rtbumi",
|
||||
"judul": "Bumi Manusia",
|
||||
"deskripsi": "<p>Kisah kehidupan Minke di masa kolonial yang menggambarkan perjuangan, pendidikan, dan identitas bangsa</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqc7bdzu",
|
||||
"imageId": "cmkqhed8x0003vneakx0c7me2"
|
||||
"imageName": "71eZShq4FYAFLxpLfZB0W-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqhg1g70008vneajbpz8phh",
|
||||
"judul": "Atomic Habits",
|
||||
"deskripsi": "<p>Panduan membangun kebiasaan kecil yang konsisten untuk menghasilkan perubahan besar dalam hidup</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqf7bdzu",
|
||||
"imageId": "cmkqhg1cb0006vneagsxa6t4t"
|
||||
"imageName": "Uxq3GXPqh7HN9fHmRkr3r-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqhl6sr000bvneampx0svus",
|
||||
"judul": "Clean Code",
|
||||
"deskripsi": "<p>Buku wajib programmer tentang cara menulis kode yang bersih, mudah dibaca, dan mudah dirawat</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqd7bdzu",
|
||||
"imageId": "cmkqhl6mv0009vneasgix42ud"
|
||||
"imageName": "W5Fc0uRADNkIY3nZicvQA-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqhoaa1000evnearppgpyxo",
|
||||
"judul": "Sejarah Indonesia Modern",
|
||||
"deskripsi": "<p>Membahas perjalanan sejarah Indonesia dari masa kolonial hingga era modern</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqc7bdzu",
|
||||
"imageId": "cmkqhoa5w000cvneah15n28zq"
|
||||
"imageName": "mp77Op-MwtPQZnH3so4JY-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqhr9oc000hvnea677ad3kb",
|
||||
"judul": "Ensiklopedia Anak Pintar",
|
||||
"deskripsi": "<p>Buku referensi bergambar yang membantu anak mengenal ilmu pengetahuan secara menyenangkan</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqh7bdzu",
|
||||
"imageId": "cmkqhr9lg000fvneai3q8qw0s"
|
||||
"imageName": "V09ZxN1wOwbSFLQiDK0VQ-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqi5ksf000kvnea9c04n2hy",
|
||||
"judul": "Filosofi Teras",
|
||||
"deskripsi": "<p>Pengenalan filsafat Stoikisme untuk menghadapi kehidupan modern dengan lebih tenang</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq87bdzu",
|
||||
"imageId": "cmkqi5knc000ivnea8grp7j06"
|
||||
"imageName": "Wqp4AyVkGjqRMED9Q5XAs-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqi97hq000nvneaparjbcrm",
|
||||
"judul": "Pemrograman JavaScript Dasar",
|
||||
"deskripsi": "<p>Panduan dasar belajar JavaScript untuk pemula dalam dunia pengembangan web</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqd7bdzu",
|
||||
"imageId": "cmkqi9799000lvneamskmvpq5"
|
||||
"imageName": "NH4aLc7cVuutdQBCofTC0-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqibjt9000qvnea13ox7fmv",
|
||||
"judul": "Pendidikan Karakter",
|
||||
"deskripsi": "<p>Buku yang membahas pentingnya pendidikan karakter dalam membentuk generasi bangsa</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqf7bdzu",
|
||||
"imageId": "cmkqibjj2000ovnea3zmmvdop"
|
||||
"imageName": "MLrsPrD6oiHsrNP4Lc8J7-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqidnar000tvneaohk5v8k6",
|
||||
"judul": "Psikologi Kepribadian",
|
||||
"deskripsi": "<p>Mengenal teori-teori kepribadian manusia dalam perspektif psikologi</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq87bdzu",
|
||||
"imageId": "cmkqidn7e000rvnea5rl58f2e"
|
||||
"imageName": "iaIeNdhuxqltqKP7aZncQ-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqifdiu000wvnea7xd0yi4f",
|
||||
"judul": "Ayat-Ayat Cinta",
|
||||
"deskripsi": "<p>Novel religi yang mengangkat kisah cinta, iman, dan perjuangan hidup</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqe7bdzu",
|
||||
"imageId": "cmkqifdfs000uvneajss8zswp"
|
||||
"imageName": "WUDssJ59pTKE_3IuTiZ2s-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqik7vi000zvneae7d5cq9i",
|
||||
"judul": "Negeri 5 Menara",
|
||||
"deskripsi": "<p>Cerita persahabatan dan perjuangan santri dalam mengejar mimpi hingga ke mancanegara</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq76bdzu",
|
||||
"imageId": "cmkqik7p5000xvnea6krii3vw"
|
||||
"imageName": "RJH_-4_R_nlP7GVEQeD1M-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqinno30012vneac1sgsvis",
|
||||
"judul": "Belajar UI/UX Design",
|
||||
"deskripsi": "<p>Panduan praktis memahami desain antarmuka dan pengalaman pengguna</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqd7bdzu",
|
||||
"imageId": "cmkqinnih0010vneakpjb9egl"
|
||||
"imageName": "9MA-Jx_36uoho2Tg40_G9-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqiqegd0015vneawv5u5tpm",
|
||||
"judul": "Manajemen Waktu Efektif",
|
||||
"deskripsi": "<p>Teknik mengatur waktu agar lebih produktif dan fokus pada hal penting</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqf7bdzu",
|
||||
"imageId": "cmkqiqeb60013vnea2ygrq5rs"
|
||||
"imageName": "dkb7ZWFl28TREVcvH8sWd-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqiurc60018vneavyd3pj9q",
|
||||
"judul": "Dongeng Nusantara",
|
||||
"deskripsi": "<p>Kumpulan dongeng tradisional Indonesia yang sarat pesan moral</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq76bdzu",
|
||||
"imageId": "cmkqiur960016vnea3werdoey"
|
||||
"imageName": "nVj3one6CLuWRd04QnsWo-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqix2kb001bvnea5v81cw7p",
|
||||
"judul": "Ekonomi Makro",
|
||||
"deskripsi": "<p>Pembahasan konsep ekonomi makro secara sistematis dan mudah dipahami</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq87bdzu",
|
||||
"imageId": "cmkqix2go0019vnea8coousvn"
|
||||
"imageName": "AnB7JO4_6tlPTX3ypOVLi-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqiyts2001evneahnk45ry5",
|
||||
"judul": "Seni Berpikir Kritis",
|
||||
"deskripsi": "<p>Buku yang membantu pembaca menghindari kesalahan berpikir dalam pengambilan keputusan</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq87bdzu",
|
||||
"imageId": "cmkqiytnv001cvnea7o2sv1vt"
|
||||
"imageName": "sAyoMERxL6JgFfiO22KPb-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqj0nq0001hvnea06r8m3kj",
|
||||
"judul": "Seni Berpikir Kritis",
|
||||
"deskripsi": "<p>Buku yang membantu pembaca menghindari kesalahan berpikir dalam pengambilan keputusan</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq87bdzu",
|
||||
"imageId": "cmkqj0nn0001fvneaufur3nke"
|
||||
"imageName": "WeA-JP2Ks_32fv1k529vj-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqj37w4001kvnea04n9w2bx",
|
||||
"judul": "Panduan Shalat Lengkap",
|
||||
"deskripsi": "<p>Panduan praktis dan lengkap tentang tata cara shalat sesuai tuntunan</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqe7bdzu",
|
||||
"imageId": "cmkqj37rg001ivneam29fgayr"
|
||||
"imageName": "pxlHu2kDmIprQqC2PuXaL-mobile.webp"
|
||||
},
|
||||
{
|
||||
"id": "cmkqj5qp6001nvnea4xhvluz3",
|
||||
"judul": "Cerita Sains untuk Anak",
|
||||
"deskripsi": "<p>Cerita edukatif yang mengenalkan sains kepada anak dengan bahasa sederhana</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqh7bdzu",
|
||||
"imageId": "cmkqj5ql6001lvnea6p0afr9f"
|
||||
"imageName": "G0iELZb2DhQDCCP5OdzJR-desktop.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fq776000104jscnj58sgm",
|
||||
"judul": "Pedagogy of the Oppressed",
|
||||
"deskripsi": "<p>Klasik pemikiran pendidikan kritis; menggali hubungan guru-murid dan peran pendidikan dalam pembebasan sosial</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq97bdzu",
|
||||
"imageName": "pendidikan-1.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fqurm000204js5p60hkym",
|
||||
"judul": "The Courage to Teach",
|
||||
"deskripsi": "<p>Tentang refleksi diri seorang pendidik; cocok untuk pengajar yang ingin lebih dari sekedar “metode mengajar”</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibq97bdzu",
|
||||
"imageName": "pendidikan-2.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fqurm000204js5p60hkzn",
|
||||
"judul": "A Brief History of Time",
|
||||
"deskripsi": "<p>Penjelasan kosmologi yang terkenal dunia; sains kompleks dibahas dengan bahasa yang bisa dinikmati pembaca umum</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqa7bdzu",
|
||||
"imageName": "ilmiah-1.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fqurm000204js5p60hkao",
|
||||
"judul": "The Selfish Gene",
|
||||
"deskripsi": "<p>Membawa perspektif baru tentang evolusi melalui “gen” sebagai unit seleksi</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqa7bdzu",
|
||||
"imageName": "ilmiah-2.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fx09c000304jshams3xbg",
|
||||
"judul": "A Little Life",
|
||||
"deskripsi": "<p>Novel yang menggambarkan hidup seorang remaja yang mengalami kehidupan yang sangat sulit</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqb7bdzu",
|
||||
"imageName": "drama-1.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fx09c000304jshams3xch",
|
||||
"judul": "Death of a Salesman",
|
||||
"deskripsi": "<p>Drama teater klasik Amerika tentang harapan, keluarga, dan realitas hidup.</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqb7bdzu",
|
||||
"imageName": "drama-2.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fx09c000304jshams3xdi",
|
||||
"judul": "How Not to Die",
|
||||
"deskripsi": "<p>Panduan berbasis penelitian tentang pola makan untuk mencegah dan menangani penyakit.</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqg7bdzu",
|
||||
"imageName": "kesehatan-1.webp"
|
||||
},
|
||||
{
|
||||
"id": "cml7fx09c000304jshams3xej",
|
||||
"judul": "The Body Keeps the Score",
|
||||
"deskripsi": "<p>Fokus pada trauma, otak & tubuh; penting untuk memahami kesehatan mental secara mendalam.</p>",
|
||||
"kategoriId": "cmkqb11mc000104jibqg7bdzu",
|
||||
"imageName": "kesehatan-2.webp"
|
||||
}
|
||||
]
|
||||
|
||||
246
prisma/lib/create_file_share_folder.ts
Normal file
246
prisma/lib/create_file_share_folder.ts
Normal file
@@ -0,0 +1,246 @@
|
||||
// import { getValidAuthToken } from "../../src/lib/seafile-auth-service";
|
||||
|
||||
// type CdnItem = {
|
||||
// name: string;
|
||||
// path: string;
|
||||
// cdnUrl: string;
|
||||
// };
|
||||
|
||||
// type DirItem = {
|
||||
// type: "file" | "dir";
|
||||
// name: string;
|
||||
// };
|
||||
|
||||
// const BASE_URL = process.env.SEAFILE_BASE_URL!;
|
||||
// const REPO_ID = process.env.SEAFILE_REPO_ID!;
|
||||
|
||||
// // folder yang dishare (RELATIVE, tanpa slash depan)
|
||||
// const DIR_TARGET = "asset-web";
|
||||
|
||||
// // 🔑 TOKEN DIRECTORY SHARE (/d/{token})
|
||||
// const PUBLIC_SHARE_TOKEN = process.env.SEAFILE_PUBLIC_SHARE_TOKEN!;
|
||||
|
||||
// /**
|
||||
// * Ambil list file dari repo (butuh token sekali)
|
||||
// */
|
||||
// async function getDirItems(): Promise<DirItem[]> {
|
||||
// const token = await getValidAuthToken();
|
||||
|
||||
// // Validasi bahwa semua variabel lingkungan telah diatur
|
||||
// if (!BASE_URL) {
|
||||
// throw new Error('SEAFILE_BASE_URL environment variable is not set');
|
||||
// }
|
||||
|
||||
// if (!REPO_ID) {
|
||||
// throw new Error('SEAFILE_REPO_ID environment variable is not set');
|
||||
// }
|
||||
|
||||
// // Bangun URL dan pastikan valid
|
||||
// const url = `${BASE_URL}/api2/repos/${REPO_ID}/dir/?p=/${DIR_TARGET}`;
|
||||
|
||||
// try {
|
||||
// new URL(url); // Ini akan melempar error jika URL tidak valid
|
||||
// } catch (error) {
|
||||
// throw new Error(`Invalid URL constructed: ${url}. Error: ${error}`);
|
||||
// }
|
||||
|
||||
// const res = await fetch(url, {
|
||||
// headers: {
|
||||
// Authorization: `Token ${token}`,
|
||||
// },
|
||||
// });
|
||||
|
||||
// if (!res.ok) {
|
||||
// const text = await res.text();
|
||||
// throw new Error(`Failed get dir items: ${text}`);
|
||||
// }
|
||||
|
||||
// return res.json();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Build PUBLIC CDN URL
|
||||
// */
|
||||
// function buildPublicCdnUrl(fileName: string) {
|
||||
// return `${BASE_URL}/d/${PUBLIC_SHARE_TOKEN}/files/?p=${encodeURIComponent(
|
||||
// fileName,
|
||||
// )}&raw=1`;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Ambil semua PUBLIC CDN URL
|
||||
// */
|
||||
// export async function getAllPublicCdnUrls(): Promise<CdnItem[]> {
|
||||
// const items = await getDirItems();
|
||||
|
||||
// return items
|
||||
// .filter((item) => item.type === "file")
|
||||
// .map((file) => {
|
||||
// const path = `${DIR_TARGET}/${file.name}`;
|
||||
// return {
|
||||
// name: file.name,
|
||||
// path,
|
||||
// cdnUrl: buildPublicCdnUrl(file.name),
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Run langsung (optional)
|
||||
// */
|
||||
// if (import.meta.main) {
|
||||
// const data = await getAllPublicCdnUrls();
|
||||
// console.log(data);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// import { getValidAuthToken } from "../../src/lib/seafile-auth-service";
|
||||
|
||||
// type CdnItem = {
|
||||
// name: string;
|
||||
// path: string;
|
||||
// cdnUrl: string;
|
||||
// };
|
||||
|
||||
// type DirItem = {
|
||||
// type: "file" | "dir";
|
||||
// name: string;
|
||||
// };
|
||||
|
||||
// // ✅ PAKAI ENV YANG BENAR
|
||||
// const BASE_URL = process.env.SEAFILE_URL!;
|
||||
// const REPO_ID = process.env.SEAFILE_REPO_ID!;
|
||||
// const PUBLIC_SHARE_TOKEN = process.env.SEAFILE_PUBLIC_SHARE_TOKEN!;
|
||||
|
||||
// // folder yang dishare (RELATIVE, TANPA slash depan)
|
||||
// const DIR_TARGET = "asset-web";
|
||||
|
||||
// /**
|
||||
// * Ambil list file dari repo (token dipakai SEKALI)
|
||||
// */
|
||||
// async function getDirItems(): Promise<DirItem[]> {
|
||||
// if (!BASE_URL || !REPO_ID) {
|
||||
// throw new Error("SEAFILE env not configured correctly");
|
||||
// }
|
||||
|
||||
// const token = await getValidAuthToken();
|
||||
|
||||
// const url = `${BASE_URL}/api2/repos/${REPO_ID}/dir/?p=/${DIR_TARGET}`;
|
||||
|
||||
// const res = await fetch(url, {
|
||||
// headers: {
|
||||
// Authorization: `Token ${token}`,
|
||||
// },
|
||||
// });
|
||||
|
||||
// if (!res.ok) {
|
||||
// const text = await res.text();
|
||||
// throw new Error(`Failed get dir items: ${text}`);
|
||||
// }
|
||||
|
||||
// return res.json();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Build PUBLIC CDN URL (DIRECTORY SHARE)
|
||||
// */
|
||||
// function buildPublicCdnUrl(fileName: string) {
|
||||
// const fullPath = `/${DIR_TARGET}/${fileName}`;
|
||||
// return `${BASE_URL}/d/${PUBLIC_SHARE_TOKEN}/files/?p=${encodeURIComponent(
|
||||
// fullPath,
|
||||
// )}&raw=1`;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Ambil semua PUBLIC CDN URL
|
||||
// */
|
||||
// export async function getAllPublicCdnUrls(): Promise<CdnItem[]> {
|
||||
// const items = await getDirItems();
|
||||
|
||||
// return items
|
||||
// .filter((item) => item.type === "file")
|
||||
// .map((file) => ({
|
||||
// name: file.name,
|
||||
// path: `${DIR_TARGET}/${file.name}`,
|
||||
// cdnUrl: buildPublicCdnUrl(file.name),
|
||||
// }));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Run langsung
|
||||
// */
|
||||
// if (import.meta.main) {
|
||||
// const data = await getAllPublicCdnUrls();
|
||||
// console.log(data);
|
||||
// }
|
||||
|
||||
|
||||
import { getValidAuthToken } from "../../src/lib/seafile-auth-service";
|
||||
type CdnItem = {
|
||||
name: string;
|
||||
path: string;
|
||||
cdnUrl: string;
|
||||
};
|
||||
type DirItem = {
|
||||
type: "file" | "dir";
|
||||
name: string;
|
||||
};
|
||||
const BASE_URL = "https://cld-dkr-makuro-seafile.wibudev.com";
|
||||
const REPO_ID = process.env.SEAFILE_REPO_ID!;
|
||||
// folder yang dishare (RELATIVE, tanpa slash depan)
|
||||
const DIR_TARGET = "asset-web";
|
||||
// 🔑 TOKEN DIRECTORY SHARE (/d/{token})
|
||||
const PUBLIC_SHARE_TOKEN = "3a9a9ecb5e244f4da8ae";
|
||||
/**
|
||||
* Ambil list file dari repo (butuh token sekali)
|
||||
*/
|
||||
async function getDirItems(): Promise<DirItem[]> {
|
||||
const token = await getValidAuthToken();
|
||||
const res = await fetch(
|
||||
`${BASE_URL}/api2/repos/${REPO_ID}/dir/?p=/${DIR_TARGET}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Token ${token}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`Failed get dir items: ${text}`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
/**
|
||||
* Build PUBLIC CDN URL
|
||||
*/
|
||||
function buildPublicCdnUrl(fileName: string) {
|
||||
return `${BASE_URL}/d/${PUBLIC_SHARE_TOKEN}/files/?p=${encodeURIComponent(
|
||||
fileName,
|
||||
)}&raw=1`;
|
||||
}
|
||||
/**
|
||||
* Ambil semua PUBLIC CDN URL
|
||||
*/
|
||||
export async function getAllPublicCdnUrls(): Promise<CdnItem[]> {
|
||||
const items = await getDirItems();
|
||||
return items
|
||||
.filter((item) => item.type === "file")
|
||||
.map((file) => {
|
||||
// const path = `${DIR_TARGET}/${file.name}`;
|
||||
const path = `/${file.name}`;
|
||||
return {
|
||||
name: file.name,
|
||||
path,
|
||||
cdnUrl: buildPublicCdnUrl(file.name),
|
||||
};
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Run langsung (optional)
|
||||
*/
|
||||
if (import.meta.main) {
|
||||
const data = await getAllPublicCdnUrls();
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getValidAuthToken } from "../../src/lib/seafile-auth-service";
|
||||
|
||||
type DirItem = {
|
||||
type: "file" | "dir";
|
||||
name: string;
|
||||
@@ -5,7 +7,6 @@ type DirItem = {
|
||||
size?: number;
|
||||
};
|
||||
|
||||
const TOKEN = process.env.SEAFILE_TOKEN!;
|
||||
const REPO_ID = process.env.SEAFILE_REPO_ID!;
|
||||
|
||||
// ⛔ PENTING: RELATIVE PATH (tanpa slash depan)
|
||||
@@ -13,11 +14,12 @@ const DIR_TARGET = "asset-web";
|
||||
|
||||
const BASE_URL = process.env.SEAFILE_URL;
|
||||
|
||||
const headers = {
|
||||
Authorization: `Token ${TOKEN}`,
|
||||
};
|
||||
|
||||
async function getDirItems(): Promise<DirItem[]> {
|
||||
const token = await getValidAuthToken();
|
||||
const headers = {
|
||||
Authorization: `Token ${token}`,
|
||||
};
|
||||
|
||||
const res = await fetch(`${BASE_URL}/repos/${REPO_ID}/dir/?p=${DIR_TARGET}`, {
|
||||
headers,
|
||||
});
|
||||
@@ -30,6 +32,11 @@ async function getDirItems(): Promise<DirItem[]> {
|
||||
}
|
||||
|
||||
async function getDownloadUrl(filePath: string): Promise<string> {
|
||||
const token = await getValidAuthToken();
|
||||
const headers = {
|
||||
Authorization: `Token ${token}`,
|
||||
};
|
||||
|
||||
const res = await fetch(
|
||||
`${BASE_URL}/repos/${REPO_ID}/file/?p=${encodeURIComponent(filePath)}&reuse=1`,
|
||||
{ headers },
|
||||
|
||||
71
prisma/lib/get_shared_images.ts
Normal file
71
prisma/lib/get_shared_images.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
//ini code awal cari image by folder di seafile
|
||||
|
||||
|
||||
type CdnItem = {
|
||||
name: string;
|
||||
path: string;
|
||||
cdnUrl: string;
|
||||
};
|
||||
|
||||
const BASE_URL = "https://cld-dkr-makuro-seafile.wibudev.com";
|
||||
const SHARE_ID = "3325e9db2c504ebf9584";
|
||||
|
||||
// https://cld-dkr-makuro-seafile.wibudev.com/d/3a9a9ecb5e244f4da8ae/
|
||||
// https://cld-dkr-makuro-seafile.wibudev.com/d/3a9a9ecb5e244f4da8ae/files/?p=-M_tICRVz6ZxOfvkuHQgU-mobile.webp&raw=1
|
||||
|
||||
|
||||
/**
|
||||
* Build CDN URL langsung (tanpa API, tanpa token)
|
||||
*/
|
||||
export function buildCdnUrl(filePath: string) {
|
||||
// filePath contoh: "banner/home.jpg"
|
||||
return `${BASE_URL}/f/${SHARE_ID}/${filePath}?raw=1`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ambil daftar file dari PUBLIC SHARE (optional)
|
||||
* Tidak pakai token
|
||||
*/
|
||||
async function getPublicDirItems(path = "/"): Promise<any[]> {
|
||||
const res = await fetch(
|
||||
`${BASE_URL}/api/v2.1/share-links/${SHARE_ID}/dir/?p=${encodeURIComponent(
|
||||
path,
|
||||
)}`,
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`Failed get public dir items: ${text}`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ambil semua CDN URL dari folder public share
|
||||
*/
|
||||
export async function getAllCdnUrls(
|
||||
dirPath = "/",
|
||||
): Promise<CdnItem[]> {
|
||||
const items = await getPublicDirItems(dirPath);
|
||||
|
||||
return items
|
||||
.filter((item: any) => item.type === "file")
|
||||
.map((file: any) => {
|
||||
const filePath =
|
||||
dirPath === "/"
|
||||
? file.name
|
||||
: `${dirPath.replace(/\/$/, "")}/${file.name}`;
|
||||
|
||||
return {
|
||||
name: file.name,
|
||||
path: filePath,
|
||||
cdnUrl: buildCdnUrl(filePath),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if(import.meta.main) {
|
||||
const allCdnUrls = await getAllCdnUrls();
|
||||
console.log(allCdnUrls);
|
||||
}
|
||||
33
prisma/lib/get_sharef.ts
Normal file
33
prisma/lib/get_sharef.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
const BASE_URL = "https://cld-dkr-makuro-seafile.wibudev.com";
|
||||
const ADMIN_TOKEN = process.env.SEAFILE_TOKEN!;
|
||||
const REPO_ID = process.env.SEAFILE_REPO_ID!;
|
||||
|
||||
export async function createFileShareForFolder() {
|
||||
const res = await fetch(`${BASE_URL}/api/v2.1/share-links/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Token ${ADMIN_TOKEN}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
repo_id: REPO_ID,
|
||||
path: "/asset-web", // FOLDER
|
||||
permission: "r",
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
console.log("FILE SHARE LINK:", data);
|
||||
|
||||
// data.link -> https://domain/f/XXXX/
|
||||
// data.token / data.id (tergantung versi)
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
await createFileShareForFolder();
|
||||
}
|
||||
@@ -1659,8 +1659,8 @@ model DesaDigital {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
deskripsi String @db.Text
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -1766,8 +1766,8 @@ model PengaduanMasyarakat {
|
||||
nik String
|
||||
judulPengaduan String
|
||||
lokasiKejadian String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
deskripsiPengaduan String @db.Text
|
||||
jenisPengaduan JenisPengaduan @relation(fields: [jenisPengaduanId], references: [id])
|
||||
jenisPengaduanId String
|
||||
@@ -1848,8 +1848,8 @@ model KegiatanDesa {
|
||||
tanggal DateTime
|
||||
lokasi String
|
||||
partisipan Int
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
@@ -2133,8 +2133,8 @@ model DataPerpustakaan {
|
||||
deskripsi String @db.Text
|
||||
kategori KategoriBuku @relation(fields: [kategoriId], references: [id])
|
||||
kategoriId String
|
||||
image FileStorage @relation(fields: [imageId], references: [id])
|
||||
imageId String
|
||||
image FileStorage? @relation(fields: [imageId], references: [id])
|
||||
imageId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
deletedAt DateTime @default(now())
|
||||
|
||||
571
prisma/seed.ts
571
prisma/seed.ts
@@ -53,21 +53,24 @@ import { seedLayananOnlineDesa } from "./_seeder_list/inovasi/seed_layanan_onlin
|
||||
import { seedProgramKreatifDesa } from "./_seeder_list/inovasi/seed_program_kreatif_desa";
|
||||
import { seedKolaborasiInovasi } from "./_seeder_list/inovasi/seed_kolaborasi_inovasi";
|
||||
import { seedInfoTeknologi } from "./_seeder_list/inovasi/seed_info_teknologi";
|
||||
import { seedPengelolaanSampah } from "./_seeder_list/lingkungan/seed_pengelolaan_sampah";
|
||||
import { seedProgramPenghijauan } from "./_seeder_list/lingkungan/seed_program_penghijauan";
|
||||
import { seedDataLingkunganDesa } from "./_seeder_list/lingkungan/seed_data_lingkungan_desa";
|
||||
import { seedDataGotongRoyong } from "./_seeder_list/lingkungan/seed_data_gotong_royong";
|
||||
import { seedEdukasiLingkungan } from "./_seeder_list/lingkungan/seed_edukasi_lingkungan";
|
||||
import { seedKonservasiAdatBali } from "./_seeder_list/lingkungan/seed_konservasi_adat_bali";
|
||||
import { seedInfoSekolah } from "./_seeder_list/pendidikan/seed_info_sekolah";
|
||||
import { seedInfoProgramPendidikan } from "./_seeder_list/pendidikan/seed_info_program_pendidikan";
|
||||
import { seedBimbinganBelajar } from "./_seeder_list/pendidikan/seed_bimbingan_belajar";
|
||||
import { seedDataPendidikan } from "./_seeder_list/pendidikan/seed_data_pendidikan";
|
||||
import { seedPendidikanNonFormal } from "./_seeder_list/pendidikan/seed_pendidikan_non_formal";
|
||||
import { seedDataPerpustakaan } from "./_seeder_list/pendidikan/seed_data_perpustakaan";
|
||||
import { seedProfilPpd } from "./_seeder_list/ppid/profil-ppid/seed_profil_ppd";
|
||||
|
||||
(async () => {
|
||||
const totalFiles = await prisma.fileStorage.count();
|
||||
|
||||
const hasImageAsset = await prisma.fileStorage.findFirst({
|
||||
where: { category: "image" },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (totalFiles === 0 || !hasImageAsset) {
|
||||
console.log("📂 fileStorage not ready, seeding assets...");
|
||||
await seedAssets();
|
||||
} else {
|
||||
console.log("ℹ️ fileStorage already initialized, skipping asset seed");
|
||||
}
|
||||
// Always run seedAssets to handle new images without duplication
|
||||
console.log("📂 Checking for new assets to seed...");
|
||||
await seedAssets();
|
||||
|
||||
// // =========== FILE STORAGE ===========
|
||||
|
||||
@@ -177,6 +180,9 @@ import { seedInfoTeknologi } from "./_seeder_list/inovasi/seed_info_teknologi";
|
||||
|
||||
// // =========== MENU PPID ===========
|
||||
|
||||
// // =========== SUBMENU PROFIL PPID ===========
|
||||
await seedProfilPpd();
|
||||
|
||||
// // =========== SUBMENU STRUKTUR PPID ===========
|
||||
await seedPegawaiPpid();
|
||||
|
||||
@@ -279,7 +285,7 @@ import { seedInfoTeknologi } from "./_seeder_list/inovasi/seed_info_teknologi";
|
||||
await seedProgramKemiskinan();
|
||||
|
||||
// // ==================== SUBMENU SEKTOR UNGGULAN DESA =============
|
||||
await seedSektorUnggulanDesa();
|
||||
await seedSektorUnggulanDesa();
|
||||
|
||||
// // ==================== SUBMENU DEMOGRAFI PEKERJAAN =============
|
||||
await seedDemografiPekerjaan();
|
||||
@@ -303,554 +309,41 @@ import { seedInfoTeknologi } from "./_seeder_list/inovasi/seed_info_teknologi";
|
||||
|
||||
// // ====================== MENU LINGKUNGAN ==========================
|
||||
// // ==================== SUBMENU PENGELOLAAN SAMPAH ==========
|
||||
// console.log("🔄 Seeding Pengelolaan Sampah...");
|
||||
// for (const p of pengelolaanSampah) {
|
||||
// await prisma.pengelolaanSampah.upsert({
|
||||
// where: {
|
||||
// id: p.id,
|
||||
// },
|
||||
// update: {
|
||||
// name: p.name,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// create: {
|
||||
// id: p.id,
|
||||
// name: p.name,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Pengelolaan Sampah seeded successfully");
|
||||
|
||||
// console.log("🔄 Seeding Keterangan Bank Sampah...");
|
||||
// for (const p of keteranganBankSampah) {
|
||||
// await prisma.keteranganBankSampahTerdekat.upsert({
|
||||
// where: {
|
||||
// id: p.id,
|
||||
// },
|
||||
// update: {
|
||||
// name: p.name,
|
||||
// alamat: p.alamat,
|
||||
// namaTempatMaps: p.namaTempatMaps,
|
||||
// linkPetunjukArah: p.linkPetunjukArah,
|
||||
// lat: p.lat,
|
||||
// lng: p.lng,
|
||||
// },
|
||||
// create: {
|
||||
// id: p.id,
|
||||
// name: p.name,
|
||||
// alamat: p.alamat,
|
||||
// namaTempatMaps: p.namaTempatMaps,
|
||||
// linkPetunjukArah: p.linkPetunjukArah,
|
||||
// lat: p.lat,
|
||||
// lng: p.lng,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Keterangan Bank Sampah seeded successfully");
|
||||
await seedPengelolaanSampah();
|
||||
|
||||
// // ==================== SUBMENU PROGRAM PENGHIJAUAN ==========
|
||||
// console.log("🔄 Seeding Program Penghijauan...");
|
||||
// for (const p of programPenghijauan) {
|
||||
// await prisma.programPenghijauan.upsert({
|
||||
// where: {
|
||||
// id: p.id,
|
||||
// },
|
||||
// update: {
|
||||
// name: p.name,
|
||||
// judul: p.judul,
|
||||
// deskripsi: p.deskripsi,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// create: {
|
||||
// id: p.id,
|
||||
// name: p.name,
|
||||
// judul: p.judul,
|
||||
// deskripsi: p.deskripsi,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Program Penghijauan seeded successfully");
|
||||
await seedProgramPenghijauan();
|
||||
|
||||
// // ==================== SUBMENU DATA LINGKUNGAN DESA ==========
|
||||
// console.log("🔄 Seeding Data Lingkungan Desa...");
|
||||
// for (const p of dataLingkunganDesa) {
|
||||
// await prisma.dataLingkunganDesa.upsert({
|
||||
// where: {
|
||||
// id: p.id,
|
||||
// },
|
||||
// update: {
|
||||
// name: p.name,
|
||||
// jumlah: p.jumlah,
|
||||
// deskripsi: p.deskripsi,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// create: {
|
||||
// id: p.id,
|
||||
// name: p.name,
|
||||
// jumlah: p.jumlah,
|
||||
// deskripsi: p.deskripsi,
|
||||
// icon: p.icon,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Data Lingkungan Desa seeded successfully");
|
||||
await seedDataLingkunganDesa();
|
||||
|
||||
// // =========== SUBMENU GOTONG ROYONG ===========
|
||||
// console.log("🔄 Seeding Kategori Gotong Royong...");
|
||||
|
||||
// for (const k of kategoriGotongRoyong) {
|
||||
// await prisma.kategoriKegiatan.upsert({
|
||||
// where: {
|
||||
// id: k.id,
|
||||
// },
|
||||
// update: {
|
||||
// nama: k.nama,
|
||||
// },
|
||||
// create: {
|
||||
// id: k.id,
|
||||
// nama: k.nama,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ Kategori Gotong Royong seeded successfully");
|
||||
|
||||
// console.log("🔄 Seeding Gotong Royong...");
|
||||
|
||||
// for (const k of gotongRoyong) {
|
||||
// await prisma.kegiatanDesa.upsert({
|
||||
// where: {
|
||||
// id: k.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: k.judul,
|
||||
// deskripsiSingkat: k.deskripsiSingkat,
|
||||
// deskripsiLengkap: k.deskripsiLengkap,
|
||||
// tanggal: k.tanggal,
|
||||
// lokasi: k.lokasi,
|
||||
// partisipan: k.partisipan,
|
||||
// imageId: k.imageId,
|
||||
// kategoriKegiatanId: k.kategoriKegiatanId,
|
||||
// },
|
||||
// create: {
|
||||
// id: k.id,
|
||||
// judul: k.judul,
|
||||
// deskripsiSingkat: k.deskripsiSingkat,
|
||||
// deskripsiLengkap: k.deskripsiLengkap,
|
||||
// tanggal: k.tanggal,
|
||||
// lokasi: k.lokasi,
|
||||
// partisipan: k.partisipan,
|
||||
// imageId: k.imageId,
|
||||
// kategoriKegiatanId: k.kategoriKegiatanId,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ Kategori Gotong Royong seeded successfully");
|
||||
await seedDataGotongRoyong();
|
||||
|
||||
// // =========== SUBMENU EDUKASI LINGKUNGAN ===========
|
||||
|
||||
// for (const e of tujuanEdukasiLingkungan) {
|
||||
// await prisma.tujuanEdukasiLingkungan.upsert({
|
||||
// where: {
|
||||
// id: e.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: e.judul,
|
||||
// deskripsi: e.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: e.id,
|
||||
// judul: e.judul,
|
||||
// deskripsi: e.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("tujuan edukasi lingkungan success ...");
|
||||
|
||||
// for (const m of materiEdukasiLingkungan) {
|
||||
// await prisma.materiEdukasiLingkungan.upsert({
|
||||
// where: {
|
||||
// id: m.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: m.judul,
|
||||
// deskripsi: m.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: m.id,
|
||||
// judul: m.judul,
|
||||
// deskripsi: m.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("materi edukasi lingkungan success ...");
|
||||
|
||||
// for (const c of contohEdukasiLingkungan) {
|
||||
// await prisma.contohEdukasiLingkungan.upsert({
|
||||
// where: {
|
||||
// id: c.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: c.judul,
|
||||
// deskripsi: c.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: c.id,
|
||||
// judul: c.judul,
|
||||
// deskripsi: c.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("contoh edukasi lingkungan success ...");
|
||||
await seedEdukasiLingkungan();
|
||||
|
||||
// // =========== SUBMENU KONSERVASI ADAT BALI ===========
|
||||
|
||||
// for (const f of filosofiTriHita) {
|
||||
// await prisma.filosofiTriHita.upsert({
|
||||
// where: {
|
||||
// id: f.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: f.judul,
|
||||
// deskripsi: f.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: f.id,
|
||||
// judul: f.judul,
|
||||
// deskripsi: f.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("filosofi tri hita success ...");
|
||||
|
||||
// for (const b of bentukKonservasiBerdasarkanAdat) {
|
||||
// await prisma.bentukKonservasiBerdasarkanAdat.upsert({
|
||||
// where: {
|
||||
// id: b.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: b.judul,
|
||||
// deskripsi: b.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: b.id,
|
||||
// judul: b.judul,
|
||||
// deskripsi: b.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("bentuk konservasi berdasarkan adat success ...");
|
||||
|
||||
// for (const n of nilaiKonservasiAdat) {
|
||||
// await prisma.nilaiKonservasiAdat.upsert({
|
||||
// where: {
|
||||
// id: n.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: n.judul,
|
||||
// deskripsi: n.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: n.id,
|
||||
// judul: n.judul,
|
||||
// deskripsi: n.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("nilai konservasi adat success ...");
|
||||
await seedKonservasiAdatBali();
|
||||
|
||||
// // ====================== MENU PENDIDIKAN ==========================
|
||||
// // =========== SUBMENU INFO SEKOLAH =====================
|
||||
|
||||
// for (const j of jenjangPendidikan) {
|
||||
// await prisma.jenjangPendidikan.upsert({
|
||||
// where: {
|
||||
// id: j.id,
|
||||
// },
|
||||
// update: {
|
||||
// nama: j.nama,
|
||||
// },
|
||||
// create: {
|
||||
// id: j.id,
|
||||
// nama: j.nama,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ Jenjang Pendidikan seeded successfully");
|
||||
|
||||
// for (const j of lembagaPendidikan) {
|
||||
// await prisma.lembaga.upsert({
|
||||
// where: {
|
||||
// id: j.id,
|
||||
// },
|
||||
// update: {
|
||||
// nama: j.nama,
|
||||
// jenjangId: j.jenjangId,
|
||||
// },
|
||||
// create: {
|
||||
// id: j.id,
|
||||
// nama: j.nama,
|
||||
// jenjangId: j.jenjangId,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ Lembaga Pendidikan seeded successfully");
|
||||
|
||||
// for (const j of siswa) {
|
||||
// await prisma.siswa.upsert({
|
||||
// where: {
|
||||
// id: j.id,
|
||||
// },
|
||||
// update: {
|
||||
// nama: j.nama,
|
||||
// lembagaId: j.lembagaId,
|
||||
// },
|
||||
// create: {
|
||||
// id: j.id,
|
||||
// nama: j.nama,
|
||||
// lembagaId: j.lembagaId,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ siswa seeded successfully");
|
||||
|
||||
// for (const j of pengajar) {
|
||||
// await prisma.pengajar.upsert({
|
||||
// where: {
|
||||
// id: j.id,
|
||||
// },
|
||||
// update: {
|
||||
// nama: j.nama,
|
||||
// lembagaId: j.lembagaId,
|
||||
// },
|
||||
// create: {
|
||||
// id: j.id,
|
||||
// nama: j.nama,
|
||||
// lembagaId: j.lembagaId,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// console.log("✅ pengajar seeded successfully");
|
||||
await seedInfoSekolah();
|
||||
|
||||
// // =========== SUBMENU PROGRAM PENDIDIKAN ANAK =====================
|
||||
|
||||
// for (const t of tujuanProgram) {
|
||||
// await prisma.tujuanProgram.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ tujuan program seeded (editable later via UI)");
|
||||
|
||||
// for (const t of programUnggulan) {
|
||||
// await prisma.programUnggulan.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ program unggulan seeded (editable later via UI)");
|
||||
await seedInfoProgramPendidikan();
|
||||
|
||||
// // =========== SUBMENU BIMBINGAN BELAJAR DESA =====================
|
||||
|
||||
// for (const t of tujuanBimbinganBelajarDesa) {
|
||||
// await prisma.tujuanBimbinganBelajarDesa.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ tujuan bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
|
||||
// for (const t of lokasiJadwalBimbinganBelajarDesa) {
|
||||
// await prisma.lokasiJadwalBimbinganBelajarDesa.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ lokasi jadwal bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
|
||||
// for (const t of fasilitasBimbinganBelajarDesa) {
|
||||
// await prisma.fasilitasBimbinganBelajarDesa.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
await seedBimbinganBelajar();
|
||||
|
||||
// // =========== SUBMENU PENDIDIKAN NON FORMAL =====================
|
||||
|
||||
// for (const t of tujuanProgram2) {
|
||||
// await prisma.tujuanPendidikanNonFormal.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
|
||||
// for (const t of tempatKegiatan) {
|
||||
// await prisma.tempatKegiatan.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
|
||||
// for (const t of jenisProgramYangDiselenggarakan) {
|
||||
// await prisma.jenisProgramYangDiselenggarakan.upsert({
|
||||
// where: { id: t.id },
|
||||
// update: {
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// create: {
|
||||
// id: t.id,
|
||||
// judul: t.judul,
|
||||
// deskripsi: t.deskripsi,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log(
|
||||
// "✅ fasilitas bimbingan belajar desa seeded (editable later via UI)",
|
||||
// );
|
||||
|
||||
await seedPendidikanNonFormal();
|
||||
// // =========== SUBMENU PERPUSTAKAAN DIGITAL =====================
|
||||
// console.log("🔄 Seeding Kategori Buku...");
|
||||
// for (const k of kategoriBuku) {
|
||||
// await prisma.kategoriBuku.upsert({
|
||||
// where: {
|
||||
// id: k.id,
|
||||
// },
|
||||
// update: {
|
||||
// name: k.name,
|
||||
// },
|
||||
// create: {
|
||||
// id: k.id,
|
||||
// name: k.name,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Kategori Buku seeded successfully");
|
||||
|
||||
// console.log("🔄 Seeding Data perpustakaan...");
|
||||
// for (const k of dataPerpustakaan) {
|
||||
// await prisma.dataPerpustakaan.upsert({
|
||||
// where: {
|
||||
// id: k.id,
|
||||
// },
|
||||
// update: {
|
||||
// judul: k.judul,
|
||||
// deskripsi: k.deskripsi,
|
||||
// kategoriId: k.kategoriId,
|
||||
// imageId: k.imageId,
|
||||
// },
|
||||
// create: {
|
||||
// id: k.id,
|
||||
// judul: k.judul,
|
||||
// deskripsi: k.deskripsi,
|
||||
// kategoriId: k.kategoriId,
|
||||
// imageId: k.imageId,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// console.log("✅ Data perpustakaan seeded successfully");
|
||||
await seedDataPerpustakaan();
|
||||
|
||||
// =========== SUBMENU DATA PENDIDIKAN =====================
|
||||
console.log("🔄 Seeding Data pendidikan...");
|
||||
for (const k of dataPendidikan) {
|
||||
await prisma.dataPendidikan.upsert({
|
||||
where: {
|
||||
id: k.id,
|
||||
},
|
||||
update: {
|
||||
name: k.name,
|
||||
jumlah: k.jumlah,
|
||||
},
|
||||
create: {
|
||||
id: k.id,
|
||||
name: k.name,
|
||||
jumlah: k.jumlah,
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log("✅ Data pendidikan seeded successfully");
|
||||
await seedDataPendidikan();
|
||||
})()
|
||||
.then(() => prisma.$disconnect())
|
||||
.catch((e) => {
|
||||
|
||||
@@ -1,43 +1,49 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import prisma from "@/lib/prisma";
|
||||
|
||||
import { getAllDownloadUrls } from "./lib/get_images";
|
||||
import { getAllPublicCdnUrls } from "./lib/create_file_share_folder";
|
||||
|
||||
export default async function seedAssets() {
|
||||
const images = await getAllDownloadUrls();
|
||||
const images = await getAllPublicCdnUrls();
|
||||
|
||||
for (const img of images) {
|
||||
try {
|
||||
await prisma.fileStorage.upsert({
|
||||
where: {
|
||||
id: img.name,
|
||||
},
|
||||
create: {
|
||||
name: img.name,
|
||||
category: "image",
|
||||
mimeType: "image/webp",
|
||||
link: img.downloadUrl,
|
||||
path: "images",
|
||||
realName: img.name,
|
||||
isActive: true,
|
||||
},
|
||||
update: {},
|
||||
// Check if the image already exists by name
|
||||
const existingImage = await prisma.fileStorage.findUnique({
|
||||
where: { name: img.name },
|
||||
});
|
||||
console.log(img.name, ": success")
|
||||
|
||||
if (!existingImage) {
|
||||
// Only create if it doesn't exist
|
||||
await prisma.fileStorage.create({
|
||||
data: {
|
||||
name: img.name,
|
||||
category: "image",
|
||||
mimeType: "image/webp",
|
||||
link: img.cdnUrl,
|
||||
path: "images",
|
||||
realName: img.name,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
console.log(`✅ Created new image: ${img.name}`);
|
||||
} else {
|
||||
console.log(`ℹ️ Image already exists, skipping: ${img.name}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("gagal seed assets", JSON.stringify(err));
|
||||
console.log(`❌ Failed to seed asset ${img.name}:`, JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🎉 Image seeding completed");
|
||||
}
|
||||
|
||||
// if (import.meta.main) {
|
||||
// seedAssets()
|
||||
// .then(() => {
|
||||
// console.log("seed assets success");
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.log("gagal seed assets", JSON.stringify(err));
|
||||
// });
|
||||
// }
|
||||
if (import.meta.main) {
|
||||
seedAssets()
|
||||
.then(() => {
|
||||
console.log("seed assets success");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("gagal seed assets", JSON.stringify(err));
|
||||
});
|
||||
}
|
||||
|
||||
21
public/manifest.json
Normal file
21
public/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Desa Darmasaba",
|
||||
"short_name": "Darmasaba",
|
||||
"description": "Website resmi Desa Darmasaba, Kabupaten Badung, Bali",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#1e40af",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/darmasaba-icon.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/darmasaba-icon.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -57,12 +57,24 @@ const stateProfilePPID = proxy({
|
||||
if (result.success) {
|
||||
this.data = result.data;
|
||||
return result.data;
|
||||
} else throw new Error(result.message || "Gagal memuat data profile");
|
||||
} else {
|
||||
// Jika pesan adalah "Data tidak ditemukan" atau "Belum ada data profil PPID yang aktif",
|
||||
// tetap simpan sebagai error tapi tidak perlu menampilkan toast error karena ini bukan error sebenarnya
|
||||
if (result.message === "Data tidak ditemukan" || result.message === "Belum ada data profil PPID yang aktif") {
|
||||
this.error = result.message;
|
||||
return null;
|
||||
} else {
|
||||
throw new Error(result.message || "Gagal memuat data profile");
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = (err as Error).message;
|
||||
this.error = msg;
|
||||
console.error("Load profile error:", msg);
|
||||
toast.error("Gagal memuat data profile");
|
||||
// Hanya tampilkan toast error jika bukan karena data tidak ditemukan
|
||||
if (msg !== "Data tidak ditemukan" && msg !== "Belum ada data profil PPID yang aktif") {
|
||||
toast.error("Gagal memuat data profile");
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
|
||||
25
src/app/admin/(dashboard)/user&role/_com/getMenuIdByRole.ts
Normal file
25
src/app/admin/(dashboard)/user&role/_com/getMenuIdByRole.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// src/app/admin/_com/getMenuIdsByRoleId.ts
|
||||
import { navBar, role1, role2, role3 } from '@/app/admin/_com/list_PageAdmin';
|
||||
|
||||
/**
|
||||
* Mengembalikan daftar ID menu (string[]) berdasarkan roleId
|
||||
*/
|
||||
export function getMenuIdsByRoleId(roleId: string | number): string[] {
|
||||
const id = typeof roleId === 'string' ? parseInt(roleId, 10) : roleId;
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
// Asumsikan devBar ada dan punya struktur sama
|
||||
return []; // atau sesuaikan jika ada devBar
|
||||
case 1:
|
||||
return navBar.map(section => section.id);
|
||||
case 2:
|
||||
return role1.map(section => section.id);
|
||||
case 3:
|
||||
return role2.map(section => section.id);
|
||||
case 4:
|
||||
return role3.map(section => section.id);
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,25 @@ export default async function profilePerbekelFindById(request: Request) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const data = await prisma.profilPerbekel.findUnique({
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.profilPerbekel.findFirst({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.profilPerbekel.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
image: true,
|
||||
image: true,
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return Response.json({
|
||||
|
||||
@@ -26,9 +26,19 @@ export default async function lambangDesaFindById(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
const data = await prisma.lambangDesa.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.lambangDesa.findFirst({
|
||||
where: { isActive: true },
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.lambangDesa.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return Response.json(
|
||||
|
||||
@@ -4,7 +4,7 @@ export default async function maskotDesaFindById(request: Request){
|
||||
const url = new URL(request.url);
|
||||
const pathSegments = url.pathname.split('/');
|
||||
const id = pathSegments[pathSegments.length - 1];
|
||||
|
||||
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
success: false,
|
||||
@@ -20,16 +20,33 @@ export default async function maskotDesaFindById(request: Request){
|
||||
}, {status: 400})
|
||||
}
|
||||
|
||||
const data = await prisma.maskotDesa.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
images: {
|
||||
include: {
|
||||
image: true,
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.maskotDesa.findFirst({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
images: {
|
||||
include: {
|
||||
image: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.maskotDesa.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
images: {
|
||||
include: {
|
||||
image: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if(!data) {
|
||||
return Response.json({
|
||||
|
||||
@@ -4,7 +4,7 @@ export default async function sejarahDesaFindById(request: Request) {
|
||||
const url = new URL(request.url);
|
||||
const pathSegments = url.pathname.split('/');
|
||||
const id = pathSegments[pathSegments.length - 1];
|
||||
|
||||
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
success: false,
|
||||
@@ -20,9 +20,19 @@ export default async function sejarahDesaFindById(request: Request) {
|
||||
}, {status: 400})
|
||||
}
|
||||
|
||||
const data = await prisma.sejarahDesa.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.sejarahDesa.findFirst({
|
||||
where: { isActive: true },
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.sejarahDesa.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return Response.json({
|
||||
|
||||
@@ -4,7 +4,7 @@ export default async function visiMisiDesaFindById(request: Request) {
|
||||
const url = new URL(request.url);
|
||||
const pathSegments = url.pathname.split('/');
|
||||
const id = pathSegments[pathSegments.length - 1];
|
||||
|
||||
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
success: false,
|
||||
@@ -20,9 +20,19 @@ export default async function visiMisiDesaFindById(request: Request) {
|
||||
}, {status: 400})
|
||||
}
|
||||
|
||||
const data = await prisma.visiMisiDesa.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.visiMisiDesa.findFirst({
|
||||
where: { isActive: true },
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.visiMisiDesa.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return Response.json({
|
||||
|
||||
@@ -20,18 +20,39 @@ export default async function handler(request: Request) {
|
||||
}, { status: 400 });
|
||||
}
|
||||
|
||||
const data = await prisma.profilePPID.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
image: true,
|
||||
}
|
||||
});
|
||||
let data;
|
||||
|
||||
// Special handling for 'edit' - get the first/only record
|
||||
if (id === 'edit') {
|
||||
data = await prisma.profilePPID.findFirst({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
orderBy: { createdAt: 'asc' } // Get the oldest one first
|
||||
});
|
||||
} else {
|
||||
data = await prisma.profilePPID.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
image: true,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return Response.json({
|
||||
success: false,
|
||||
message: "Data tidak ditemukan",
|
||||
}, { status: 404 });
|
||||
// Untuk ID 'edit', kembalikan pesan khusus karena mungkin memang belum ada data
|
||||
if (id === 'edit') {
|
||||
return Response.json({
|
||||
success: false,
|
||||
message: "Belum ada data profil PPID yang aktif",
|
||||
}, { status: 404 });
|
||||
} else {
|
||||
return Response.json({
|
||||
success: false,
|
||||
message: "Data tidak ditemukan",
|
||||
}, { status: 404 });
|
||||
}
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { getMenuIdsByRoleId } from "@/app/admin/(dashboard)/user&role/_com/getMenuIdByRole";
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
@@ -34,11 +35,25 @@ export default async function userUpdate(context: Context) {
|
||||
const isActiveChanged =
|
||||
isActive !== undefined && currentUser.isActive !== isActive;
|
||||
|
||||
// ✅ Jika role berubah, hapus semua akses menu yang ada
|
||||
if (isRoleChanged) {
|
||||
// ✅ Jika role berubah, reset dan set ulang akses menu
|
||||
if (isRoleChanged && roleId) {
|
||||
// Hapus akses lama
|
||||
await prisma.userMenuAccess.deleteMany({
|
||||
where: { userId: id }
|
||||
});
|
||||
|
||||
// Ambil menu default untuk role baru
|
||||
const menuIds = getMenuIdsByRoleId(roleId);
|
||||
|
||||
if (menuIds.length > 0) {
|
||||
// Buat akses baru
|
||||
await prisma.userMenuAccess.createMany({
|
||||
data: menuIds.map(menuId => ({
|
||||
userId: id,
|
||||
menuId
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update user
|
||||
|
||||
@@ -13,9 +13,9 @@ function VisiMisiDesa() {
|
||||
state.findUnique.load('edit');
|
||||
}, []);
|
||||
|
||||
const { data, loading } = state.findUnique;
|
||||
const { data, loading, error } = state.findUnique;
|
||||
|
||||
if (loading || !data) {
|
||||
if (loading) {
|
||||
return (
|
||||
<Box py="xl">
|
||||
<Skeleton h={500} radius="lg" />
|
||||
@@ -23,6 +23,21 @@ function VisiMisiDesa() {
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !data) {
|
||||
return (
|
||||
<Box py="xl">
|
||||
<Paper p="xl" radius="lg" shadow="md" withBorder>
|
||||
<Title order={2} c="red" ta="center" mb="md">
|
||||
Terjadi Kesalahan
|
||||
</Title>
|
||||
<Text ta="center" c="dimmed">
|
||||
{error || 'Data visi dan misi desa tidak ditemukan'}
|
||||
</Text>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack align="center" gap="xl">
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
'use client'
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Box, Text, Paper, Skeleton, Center, Title } from '@mantine/core';
|
||||
import React from 'react';
|
||||
import {
|
||||
Stack,
|
||||
Box,
|
||||
Text,
|
||||
Paper,
|
||||
Skeleton,
|
||||
Center,
|
||||
Title,
|
||||
Pagination
|
||||
} from '@mantine/core';
|
||||
import React, { useState } from 'react';
|
||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||
import { BarChart } from '@mantine/charts';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
@@ -13,11 +22,15 @@ function Page() {
|
||||
|
||||
const {
|
||||
data,
|
||||
loading,
|
||||
loading
|
||||
} = state.findMany
|
||||
|
||||
const [activePage, setActivePage] = useState(1);
|
||||
const itemsPerPage = 3;
|
||||
|
||||
useShallowEffect(() => {
|
||||
state.findMany.load()
|
||||
// Muat semua data tanpa batasan jumlah per halaman
|
||||
state.findMany.load() // Ambil banyak data sekaligus
|
||||
}, [])
|
||||
|
||||
if (loading || !data) {
|
||||
@@ -44,6 +57,11 @@ function Page() {
|
||||
);
|
||||
}
|
||||
|
||||
// Filter data untuk halaman saat ini
|
||||
const startIndex = (activePage - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
const currentData = data.slice(startIndex, endIndex);
|
||||
|
||||
const chartData = data
|
||||
.filter(item => item?.name && typeof item.value === 'number')
|
||||
.map((item) => ({
|
||||
@@ -74,9 +92,9 @@ function Page() {
|
||||
</Box>
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Stack gap="lg" justify="center">
|
||||
{data.map((v, k) => {
|
||||
{currentData.map((v, k) => {
|
||||
return (
|
||||
<Paper p="xl" key={k}>
|
||||
<Paper p="xl" key={`${startIndex + k}`}>
|
||||
<Title order={3} fw="bold">
|
||||
{v.name}
|
||||
</Title>
|
||||
@@ -90,6 +108,18 @@ function Page() {
|
||||
</Paper>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Pagination */}
|
||||
<Center mt="xl">
|
||||
<Pagination
|
||||
total={Math.ceil(data.length / itemsPerPage)}
|
||||
value={activePage}
|
||||
onChange={setActivePage}
|
||||
size="lg"
|
||||
radius="md"
|
||||
/>
|
||||
</Center>
|
||||
|
||||
<Box style={{ width: '100%', overflowX: 'auto' }}>
|
||||
<Paper p="xl">
|
||||
<Title order={3} fw="bold" pb="md">
|
||||
|
||||
@@ -99,7 +99,7 @@ function Page() {
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={v.image.link}
|
||||
src={v.image?.link || "/no-image.jpg"}
|
||||
alt={v.name}
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
|
||||
@@ -162,6 +162,9 @@ function Page() {
|
||||
p="lg"
|
||||
shadow="sm"
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-4px)',
|
||||
boxShadow: '0 8px 20px rgba(0,0,0,0.1)',
|
||||
@@ -169,7 +172,7 @@ function Page() {
|
||||
transition: 'transform 0.2s ease, box-shadow 0.2s ease',
|
||||
}}
|
||||
>
|
||||
<Stack gap="sm">
|
||||
<Stack gap="sm" style={{ flex: 1 }}>
|
||||
<Text
|
||||
c={colors['blue-button']}
|
||||
lineClamp={2}
|
||||
@@ -190,7 +193,7 @@ function Page() {
|
||||
: '-'}
|
||||
</Text>
|
||||
|
||||
<Box>
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Text fw="bold" fz="sm">
|
||||
Penanganan:
|
||||
</Text>
|
||||
@@ -257,6 +260,7 @@ function Page() {
|
||||
onClick={() => router.push(`/darmasaba/keamanan/laporan-publik/${v.id}`)}
|
||||
size={mobile ? 'sm' : 'md'}
|
||||
fullWidth
|
||||
style={{ marginTop: 'auto' }}
|
||||
>
|
||||
{mobile ? 'Detail' : 'Lihat Detail Kronologi'}
|
||||
</Button>
|
||||
|
||||
@@ -55,9 +55,9 @@ function Page() {
|
||||
<SimpleGrid
|
||||
px={{ base: 20, md: 100 }}
|
||||
cols={{ base: 1, md: 2 }}
|
||||
spacing="xl"
|
||||
spacing={{ base: 'md', md: 'xl' }}
|
||||
>
|
||||
<Paper p="xl" radius="xl" shadow="lg" >
|
||||
<Paper p="xl" radius="xl" shadow="lg" bg="white">
|
||||
<Title order={2} c={colors['blue-button']} fw="bold" lh={1.2}>
|
||||
Program Keamanan Berjalan
|
||||
</Title>
|
||||
@@ -85,9 +85,9 @@ function Page() {
|
||||
<SimpleGrid
|
||||
px={{ base: 20, md: 100 }}
|
||||
cols={{ base: 1, md: 2 }}
|
||||
spacing="xl"
|
||||
spacing={{ base: 'md', md: 'xl' }}
|
||||
>
|
||||
<Paper p="xl" radius="xl" shadow="lg" >
|
||||
<Paper p="xl" radius="xl" shadow="lg" bg="white">
|
||||
<Title order={2} c={colors['blue-button']} fw="bold" lh={1.2}>
|
||||
Program Keamanan Berjalan
|
||||
</Title>
|
||||
@@ -108,6 +108,7 @@ function Page() {
|
||||
cursor: 'pointer',
|
||||
backgroundColor: colors['blue-button'],
|
||||
transition: 'all 0.2s ease',
|
||||
marginBottom: '10px' // Add space between items
|
||||
}}
|
||||
onClick={() =>
|
||||
router.push(`/darmasaba/keamanan/pencegahan-kriminalitas/${item.id}`)
|
||||
@@ -160,7 +161,7 @@ function Page() {
|
||||
{findFirst.loading ? (
|
||||
<Center><Skeleton h={400} /></Center>
|
||||
) : findFirst.data ? (
|
||||
<Paper p="xl" radius="xl" shadow="lg">
|
||||
<Paper p="xl" radius="xl" shadow="lg" bg="white">
|
||||
{findFirst.data?.linkVideo ? (
|
||||
<Box
|
||||
component="iframe"
|
||||
@@ -168,7 +169,7 @@ function Page() {
|
||||
width="100%"
|
||||
height={300}
|
||||
allowFullScreen
|
||||
style={{ borderRadius: 8 }}
|
||||
style={{ borderRadius: 8, marginBottom: 15 }}
|
||||
/>
|
||||
) : (
|
||||
<Text fz={{ base: 'xs', md: 'sm' }} c="dimmed" lh={1.4}>
|
||||
|
||||
@@ -214,14 +214,15 @@ export default function Page() {
|
||||
{paginatedNews.map((item) => (
|
||||
<Card key={item.id} shadow="sm" p="lg" radius="md" withBorder>
|
||||
<Card.Section>
|
||||
<Image
|
||||
src={item.image?.link || '/images/placeholder-small.jpg'}
|
||||
height={200}
|
||||
alt={item.judul}
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
radius={"md"}
|
||||
/>
|
||||
<Box h={160} w="100%" style={{ overflow: 'hidden' }}>
|
||||
<Image
|
||||
src={item.image?.link || '/images/placeholder-small.jpg'}
|
||||
alt={item.judul}
|
||||
fit="cover"
|
||||
loading="lazy"
|
||||
radius={"md"}
|
||||
/>
|
||||
</Box>
|
||||
</Card.Section>
|
||||
|
||||
<Badge color="blue" variant="light" mt="md">
|
||||
|
||||
@@ -119,7 +119,13 @@ export default function DetailBukuUser() {
|
||||
<ModalPeminjaman
|
||||
opened={opened}
|
||||
onClose={() => setOpened(false)}
|
||||
buku={data}
|
||||
buku={{
|
||||
id: data.id,
|
||||
judul: data.judul,
|
||||
deskripsi: data.deskripsi,
|
||||
image: data.image ? { link: data.image.link } : undefined,
|
||||
kategori: data.kategori ? { name: data.kategori.name } : undefined,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -19,19 +19,27 @@ function Content({ kategoriBuku }: { kategoriBuku: string }) {
|
||||
const searchQuery = searchParams.get('search') || '';
|
||||
const router = useTransitionRouter()
|
||||
|
||||
// Convert kebab-case back to original category name format
|
||||
// This reverses the transformation done in layoutTabs: item.name.toLowerCase().replace(/\s+/g, '-')
|
||||
const convertKebabCaseToOriginal = (kebabStr: string): string => {
|
||||
// Replace hyphens with spaces
|
||||
return kebabStr.replace(/-/g, ' ');
|
||||
};
|
||||
|
||||
const decodedKategoriBuku = decodeURIComponent(kategoriBuku);
|
||||
const originalKategoriName = convertKebabCaseToOriginal(decodedKategoriBuku);
|
||||
|
||||
const loadData = useCallback(async (searchQuery: string = '', page: number = 1) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const currentKategoriFilter = decodedKategoriBuku.toLowerCase() === 'semua' ? '' : decodedKategoriBuku;
|
||||
const currentKategoriFilter = decodedKategoriBuku.toLowerCase() === 'semua' ? '' : originalKategoriName;
|
||||
await state.dataPerpustakaan.findMany.load(page, 3, searchQuery, currentKategoriFilter);
|
||||
setCurrentPage(page);
|
||||
setTotalPages(state.dataPerpustakaan.findMany.totalPages);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [state.dataPerpustakaan.findMany, decodedKategoriBuku]);
|
||||
}, [state.dataPerpustakaan.findMany, originalKategoriName, decodedKategoriBuku]);
|
||||
|
||||
useShallowEffect(() => {
|
||||
loadData(searchQuery);
|
||||
|
||||
@@ -223,7 +223,13 @@ export default function Content() {
|
||||
fullWidth
|
||||
leftSection={<IconBook2 size={20} />}
|
||||
onClick={() => {
|
||||
setSelectedBook(v);
|
||||
setSelectedBook({
|
||||
id: v.id,
|
||||
judul: v.judul,
|
||||
deskripsi: v.deskripsi,
|
||||
image: v.image ? { link: v.image.link } : undefined,
|
||||
kategori: v.kategori ? { name: v.kategori.name } : undefined,
|
||||
});
|
||||
setOpened(true);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -34,7 +34,7 @@ function Page() {
|
||||
}, []);
|
||||
|
||||
// LOADING SKELETON
|
||||
if (!allList.profile.data)
|
||||
if (allList.profile.loading)
|
||||
return (
|
||||
<Stack bg={colors.Bg} py="xl" gap="22">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
@@ -53,6 +53,50 @@ function Page() {
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// ERROR HANDLING
|
||||
if (allList.profile.error)
|
||||
return (
|
||||
<Stack bg={colors.Bg} py="xl" gap="22" justify="center" align="center">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Paper p="xl" bg={colors['white-trans-1']} radius="lg" shadow="xl">
|
||||
{allList.profile.error === "Belum ada data profil PPID yang aktif" ? (
|
||||
<>
|
||||
<Title order={3} ta="center" c={"orange"} fw={700}>
|
||||
Data Profile PPID Belum Tersedia
|
||||
</Title>
|
||||
<Text ta="center" mt="md">Mohon maaf, data profil PPID belum tersedia saat ini</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Title order={3} ta="center" c={"red"} fw={700}>
|
||||
Gagal Memuat Data Profile
|
||||
</Title>
|
||||
<Text ta="center" mt="md">Silakan coba beberapa saat lagi</Text>
|
||||
<Text ta="center" size="sm" c={"gray"} mt="sm">
|
||||
Error: {allList.profile.error}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
// NO DATA HANDLING
|
||||
if (!allList.profile.data)
|
||||
return (
|
||||
<Stack bg={colors.Bg} py="xl" gap="22" justify="center" align="center">
|
||||
<Box px={{ base: 'md', md: 100 }}>
|
||||
<Paper p="xl" bg={colors['white-trans-1']} radius="lg" shadow="xl">
|
||||
<Title order={3} ta="center" c={"orange"} fw={700}>
|
||||
Data Profile PPID Belum Tersedia
|
||||
</Title>
|
||||
<Text ta="center" mt="md">Mohon maaf, data profil PPID belum tersedia saat ini</Text>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const dataArray = Array.isArray(allList.profile.data)
|
||||
? allList.profile.data
|
||||
: [allList.profile.data];
|
||||
|
||||
@@ -36,8 +36,67 @@ const getCurrentTime = () => {
|
||||
return `${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
const isWorkingHours = (currentTime: string): boolean => {
|
||||
const [openTime, closeTime] = ["08:00", "17:00"];
|
||||
// Fungsi untuk mendapatkan tanggal hari ini dalam format YYYY-MM-DD
|
||||
const getTodayDate = (): string => {
|
||||
const today = new Date();
|
||||
const year = today.getFullYear();
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
// Fungsi untuk memeriksa apakah tanggal tertentu adalah hari libur nasional
|
||||
// Daftar hari libur nasional Indonesia (bisa diperbarui sesuai tahun berjalan)
|
||||
const isNationalHoliday = (date: string): boolean => {
|
||||
// Format tanggal harus dalam bentuk YYYY-MM-DD
|
||||
const holidays = [
|
||||
// Tahun 2026
|
||||
'2026-01-01', // Tahun Baru Masehi
|
||||
'2026-02-17', // Isra Mikraj Nabi Muhammad SAW
|
||||
'2026-03-08', // Hari Raya Nyepi Tahun Baru Saka 1948
|
||||
'2026-04-03', // Wafat Isa Almasih
|
||||
'2026-05-01', // Hari Buruh Internasional
|
||||
'2026-05-20', // Kenaikan Isa Almasih
|
||||
'2026-06-01', // Hari Lahir Pancasila
|
||||
'2026-06-05', // Hari Raya Idul Adha
|
||||
'2026-08-17', // Hari Kemerdekaan RI
|
||||
'2026-09-21', // Tahun Baru Islam 1448 H
|
||||
'2026-10-02', // Maulid Nabi Muhammad SAW
|
||||
'2026-12-25', // Hari Raya Natal
|
||||
|
||||
// Hari raya besar lainnya
|
||||
'2026-04-06', // Hari Raya Idul Fitri
|
||||
'2026-04-07', // Hari Raya Idul Fitri
|
||||
|
||||
// Hari libur pengganti
|
||||
'2026-04-08', // Hari Libur Pengganti Idul Fitri
|
||||
'2026-04-09', // Hari Libur Pengganti Idul Fitri
|
||||
];
|
||||
|
||||
return holidays.includes(date);
|
||||
};
|
||||
|
||||
const isWorkingHours = (day: string, currentTime: string): boolean => {
|
||||
// Cek apakah hari ini hari libur nasional
|
||||
if (isNationalHoliday(getTodayDate())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let openTime = "";
|
||||
let closeTime = "";
|
||||
|
||||
// Atur jam kerja berdasarkan hari
|
||||
if (["Senin", "Selasa", "Rabu", "Kamis"].includes(day)) {
|
||||
openTime = "07:30";
|
||||
closeTime = "15:30";
|
||||
} else if (day === "Jumat") {
|
||||
openTime = "07:30";
|
||||
closeTime = "12:00";
|
||||
} else {
|
||||
// Sabtu dan Minggu tutup
|
||||
return false;
|
||||
}
|
||||
|
||||
const compareTimes = (time1: string, time2: string) => {
|
||||
const [hour1, minute1] = time1.split(":").map(Number);
|
||||
const [hour2, minute2] = time2.split(":").map(Number);
|
||||
@@ -45,18 +104,33 @@ const isWorkingHours = (currentTime: string): boolean => {
|
||||
if (hour1 > hour2) return false;
|
||||
return minute1 <= minute2;
|
||||
};
|
||||
|
||||
return compareTimes(currentTime, closeTime) && !compareTimes(currentTime, openTime);
|
||||
};
|
||||
|
||||
const getWorkStatus = (day: string, currentTime: string): { status: string; message: string } => {
|
||||
// Cek apakah hari ini hari libur nasional
|
||||
if (isNationalHoliday(getTodayDate())) {
|
||||
return { status: "Tutup", message: "Hari Libur Nasional" };
|
||||
}
|
||||
|
||||
const workingDays = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat"];
|
||||
if (!workingDays.includes(day)) {
|
||||
return { status: "Tutup", message: "Libur Akhir Pekan" };
|
||||
}
|
||||
const isOpen = isWorkingHours(currentTime);
|
||||
|
||||
const isOpen = isWorkingHours(day, currentTime);
|
||||
|
||||
let workHoursMessage = "";
|
||||
if (["Senin", "Selasa", "Rabu", "Kamis"].includes(day)) {
|
||||
workHoursMessage = "07:30 - 15:30";
|
||||
} else if (day === "Jumat") {
|
||||
workHoursMessage = "07:30 - 12:00";
|
||||
}
|
||||
|
||||
return isOpen
|
||||
? { status: "Buka", message: "08:00 - 17:00" }
|
||||
: { status: "Tutup", message: "08:00 - 17:00" };
|
||||
? { status: "Buka", message: workHoursMessage }
|
||||
: { status: "Tutup", message: workHoursMessage };
|
||||
};
|
||||
|
||||
// 🟦 Skeleton component untuk Social Media
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "@mantine/core/styles.css";
|
||||
import "./globals.css";
|
||||
import "./globals.css"; // Sisanya import di globals.css
|
||||
|
||||
import LoadDataFirstClient from "@/app/darmasaba/_com/LoadDataFirstClient";
|
||||
import {
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
MantineProvider,
|
||||
createTheme,
|
||||
mantineHtmlProps,
|
||||
// mantineHtmlProps,
|
||||
} from "@mantine/core";
|
||||
import { Metadata, Viewport } from "next";
|
||||
import { ViewTransitions } from "next-view-transitions";
|
||||
|
||||
@@ -16,6 +16,7 @@ function Page() {
|
||||
dengan ketentuan ini, harap jangan gunakan Website.
|
||||
</Text>
|
||||
</Paper>
|
||||
|
||||
|
||||
<Box>
|
||||
<Title order={2} size="h2" fw={700} c="blue.9" mb="md">
|
||||
|
||||
17
src/lib/seafile-auth-service.ts
Normal file
17
src/lib/seafile-auth-service.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// Function to get the static authentication token from environment variables
|
||||
export async function getValidAuthToken(): Promise<string> {
|
||||
const staticToken = process.env.SEAFILE_TOKEN;
|
||||
|
||||
if (!staticToken) {
|
||||
throw new Error('SEAFILE_TOKEN environment variable is not set');
|
||||
}
|
||||
|
||||
console.log("Using static SEAFILE_TOKEN from environment variables");
|
||||
|
||||
return staticToken;
|
||||
}
|
||||
|
||||
// Function to check if the token is set (always true since we're using static token)
|
||||
export function isTokenValid(): boolean {
|
||||
return !!process.env.SEAFILE_TOKEN;
|
||||
}
|
||||
68
x.json
68
x.json
@@ -1,26 +1,4 @@
|
||||
[
|
||||
{
|
||||
"type": "repo",
|
||||
"id": "8814bfe1-30d5-4e77-ab36-3122fa59a022",
|
||||
"owner": "0535ccb6211642c0a628f521577863a0@auth.local",
|
||||
"owner_name": "nico",
|
||||
"owner_contact_email": "nico@bip.com",
|
||||
"name": "desa-darmasaba",
|
||||
"mtime": 1769484147,
|
||||
"modifier_email": "0535ccb6211642c0a628f521577863a0@auth.local",
|
||||
"modifier_contact_email": "nico@bip.com",
|
||||
"modifier_name": "nico",
|
||||
"mtime_relative": "<time datetime=\"2026-01-27T11:22:27\" is=\"relative-time\" title=\"Tue, 27 Jan 2026 11:22:27 +0800\" >1 minutes ago</time>",
|
||||
"size": 184351,
|
||||
"size_formatted": "180.0\u00a0KB",
|
||||
"encrypted": false,
|
||||
"permission": "rw",
|
||||
"virtual": false,
|
||||
"root": "",
|
||||
"head_commit_id": "253fd9604e54804a22cbf701bcc551e311e4a428",
|
||||
"version": 1,
|
||||
"salt": ""
|
||||
},
|
||||
{
|
||||
"type": "repo",
|
||||
"id": "f0e9ee4a-fd13-49a2-81c0-f253951d063a",
|
||||
@@ -28,18 +6,40 @@
|
||||
"owner_name": "nico",
|
||||
"owner_contact_email": "nico@bip.com",
|
||||
"name": "My Library",
|
||||
"mtime": 1769483609,
|
||||
"mtime": 1770175246,
|
||||
"modifier_email": "0535ccb6211642c0a628f521577863a0@auth.local",
|
||||
"modifier_contact_email": "nico@bip.com",
|
||||
"modifier_name": "nico",
|
||||
"mtime_relative": "<time datetime=\"2026-01-27T11:13:29\" is=\"relative-time\" title=\"Tue, 27 Jan 2026 11:13:29 +0800\" >10 minutes ago</time>",
|
||||
"size": 19392875,
|
||||
"size_formatted": "18.5\u00a0MB",
|
||||
"mtime_relative": "<time datetime=\"2026-02-04T11:20:46\" is=\"relative-time\" title=\"Wed, 04 Feb 2026 11:20:46 +0800\" >1 day ago</time>",
|
||||
"size": 8418588,
|
||||
"size_formatted": "8.0\u00a0MB",
|
||||
"encrypted": false,
|
||||
"permission": "rw",
|
||||
"virtual": false,
|
||||
"root": "",
|
||||
"head_commit_id": "22374e711577dcfb152fe07921458302feb9970a",
|
||||
"head_commit_id": "d864f18510f72fbf7ed8601d89ced2cb92466057",
|
||||
"version": 1,
|
||||
"salt": ""
|
||||
},
|
||||
{
|
||||
"type": "repo",
|
||||
"id": "8814bfe1-30d5-4e77-ab36-3122fa59a022",
|
||||
"owner": "0535ccb6211642c0a628f521577863a0@auth.local",
|
||||
"owner_name": "nico",
|
||||
"owner_contact_email": "nico@bip.com",
|
||||
"name": "desa-darmasaba",
|
||||
"mtime": 1769486218,
|
||||
"modifier_email": "0535ccb6211642c0a628f521577863a0@auth.local",
|
||||
"modifier_contact_email": "nico@bip.com",
|
||||
"modifier_name": "nico",
|
||||
"mtime_relative": "<time datetime=\"2026-01-27T11:56:58\" is=\"relative-time\" title=\"Tue, 27 Jan 2026 11:56:58 +0800\" >9 days ago</time>",
|
||||
"size": 5064580,
|
||||
"size_formatted": "4.8\u00a0MB",
|
||||
"encrypted": false,
|
||||
"permission": "rw",
|
||||
"virtual": false,
|
||||
"root": "",
|
||||
"head_commit_id": "1ddc57ecf377741d0b3abcf5a56a9ed0612c553c",
|
||||
"version": 1,
|
||||
"salt": ""
|
||||
},
|
||||
@@ -48,12 +48,12 @@
|
||||
"id": "9ef9d5e2-6df0-4635-ae1b-53ed52801524",
|
||||
"name": "RND",
|
||||
"owner": "Organization",
|
||||
"mtime": 1768959408,
|
||||
"mtime_relative": "<time datetime=\"2026-01-21T09:36:48\" is=\"relative-time\" title=\"Wed, 21 Jan 2026 09:36:48 +0800\" >6 days ago</time>",
|
||||
"modifier_email": "dfa07fcb3e27453e969492855a2d6606@auth.local",
|
||||
"modifier_contact_email": "jun@bip.com",
|
||||
"modifier_name": "jun",
|
||||
"size": 1197897275,
|
||||
"mtime": 1770263243,
|
||||
"mtime_relative": "<time datetime=\"2026-02-05T11:47:23\" is=\"relative-time\" title=\"Thu, 05 Feb 2026 11:47:23 +0800\" >28 minutes ago</time>",
|
||||
"modifier_email": "ecb9357c59024141bc1731a3e10900ea@auth.local",
|
||||
"modifier_contact_email": "inno@bip.com",
|
||||
"modifier_name": "inno",
|
||||
"size": 1198188885,
|
||||
"size_formatted": "1.1\u00a0GB",
|
||||
"encrypted": false,
|
||||
"permission": "rw",
|
||||
@@ -62,7 +62,7 @@
|
||||
"share_from_contact_email": "wibu@bip.com",
|
||||
"share_type": "public",
|
||||
"root": "",
|
||||
"head_commit_id": "5199e27babe4fd797e64beba62777a1dde58077b",
|
||||
"head_commit_id": "f79f42f47c790bf5f14adb64bd644ec02aaf15bb",
|
||||
"version": 1,
|
||||
"salt": ""
|
||||
}
|
||||
|
||||
16
x.sh
16
x.sh
@@ -1,23 +1,23 @@
|
||||
|
||||
# ambil token
|
||||
# # ambil token
|
||||
# curl -X POST https://cld-dkr-makuro-seafile.wibudev.com/api2/auth-token/ \
|
||||
# -d "username=nico@bip.com" \
|
||||
# -d "password=Production_123"
|
||||
|
||||
# ambil list repo / library
|
||||
# # ambil list repo / library
|
||||
|
||||
TOKEN=20a19f4a04032215d50ce53292e6abdd38b9f806
|
||||
# TOKEN=20a19f4a04032215d50ce53292e6abdd38b9f806
|
||||
# curl -X GET \
|
||||
# https://cld-dkr-makuro-seafile.wibudev.com/api2/repos/ \
|
||||
# -H "Authorization: Token $TOKEN"
|
||||
|
||||
# REPO_NAME=desa-darmasaba
|
||||
DIR_TARGET=asset-web
|
||||
# DIR_TARGET=asset-web
|
||||
|
||||
REPO_ID=f0e9ee4a-fd13-49a2-81c0-f253951d063a
|
||||
curl -X GET \
|
||||
"https://cld-dkr-makuro-seafile.wibudev.com/api2/repos/$REPO_ID/dir/?p=$DIR_TARGET" \
|
||||
-H "Authorization: Token $TOKEN"
|
||||
# REPO_ID=f0e9ee4a-fd13-49a2-81c0-f253951d063a
|
||||
# curl -X GET \
|
||||
# "https://cld-dkr-makuro-seafile.wibudev.com/api2/repos/$REPO_ID/dir/?p=$DIR_TARGET" \
|
||||
# -H "Authorization: Token $TOKEN"
|
||||
|
||||
# curl -X GET \
|
||||
# "https://cld-dkr-makuro-seafile.wibudev.com/api2/repos/$REPO_ID/file/?p=$DIR_TARGET/buku6.jpg" \
|
||||
|
||||
Reference in New Issue
Block a user