106// app.dropanchor.getGlobalFeed
107app.get("/app.dropanchor.getGlobalFeed", async (c) => {
108 // Authenticate request to prevent scraping
109 const authContext = await authenticateRequest(c);
110 if (!authContext) {
1// Integration tests for API endpoints
2import { assertEquals } from "https://deno.land/std@0.208.0/assert/mod.ts";
3
147 await response.text(); // Consume response body
148
149 // Check that response includes CORS headers for API endpoints
150 assertEquals(response.status, 200);
151 // Note: Some CORS headers may be added by Val Town automatically
169});
170
171Deno.test("Integration - content-type should be JSON for API responses", async () => {
172 const response = await fetch(`${BASE_URL}/health`);
173 const data = await response.json(); // Consume as JSON instead of text
24var cookieClose;
25var cookieBanner;
26var baseUrl_dev_env = "https://api-dev.lelivrescolaire.fr";
27var baseUrl_prod_env = "https://api.lelivrescolaire.fr";
28var checkDev = new RegExp(/www\.lelivrescolaire\.fr|^lelivrescolaire\.fr/g);
29var baseUrl = checkDev.test(document.location.hostname)
202}
203
204function capitalizeFirstLetter(str) {
205 return str.trim().charAt(0).toUpperCase() + str.trim().slice(1).toLowerCase();
206}
114- `vip_levels_v2` - VIP āϞā§āĻā§āϞ āĻāύāĻĢāĻŋāĻāĻžāϰā§āĻļāύ
115
116## đ§ API Endpoints
117
118### Authentication
119- `POST /api/auth/register` - āύāϤā§āύ āĻāĻāĻžāĻāύā§āĻ āϤā§āϰāĻŋ
120- `POST /api/auth/login` - āϞāĻāĻāύ
121- `POST /api/auth/verify` - āĻā§āĻā§āύ āϝāĻžāĻāĻžāĻ
122
123### Tasks
124- `GET /api/tasks` - āĻāĻžāϏā§āĻ āϤāĻžāϞāĻŋāĻāĻž
125- `POST /api/tasks/complete` - āĻāĻžāϏā§āĻ āϏāĻŽā§āĻĒāύā§āύ
126- `GET /api/tasks/history` - āĻāĻžāϏā§āĻ āĻāϤāĻŋāĻšāĻžāϏ
127- `GET /api/tasks/today-summary` - āĻāĻāĻā§āϰ āϏāĻžāĻŽāĻžāϰāĻŋ
128
129### Payments
130- `GET /api/payments/transactions` - āϞā§āύāĻĻā§āύā§āϰ āĻāϤāĻŋāĻšāĻžāϏ
131- `POST /api/payments/deposit` - āĻĄāĻŋāĻĒā§āĻāĻŋāĻ āϰāĻŋāĻā§āϝāĻŧā§āϏā§āĻ
132- `POST /api/payments/withdraw` - āĻāĻāĻĨāĻĄā§āϰ āϰāĻŋāĻā§āϝāĻŧā§āϏā§āĻ
133- `GET /api/payments/vip-levels` - VIP āϞā§āĻā§āϞ āϤāĻžāϞāĻŋāĻāĻž
134- `GET /api/payments/methods` - āĻĒā§āĻŽā§āύā§āĻ āĻŽā§āĻĨāĻĄ
135
136### Admin
137- `POST /api/admin/login` - āĻāĻĄāĻŽāĻŋāύ āϞāĻāĻāύ
138- `GET /api/admin/dashboard` - āĻĄā§āϝāĻžāĻļāĻŦā§āϰā§āĻĄ āϏā§āĻā§āϝāĻžāĻāϏ
139- `GET /api/admin/users` - āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āϤāĻžāϞāĻŋāĻāĻž
140- `GET /api/admin/transactions` - āϞā§āύāĻĻā§āύ āϤāĻžāϞāĻŋāĻāĻž
141- `POST /api/admin/transactions/:id/status` - āϞā§āύāĻĻā§āύ āĻ
āύā§āĻŽā§āĻĻāύ
142- `POST /api/admin/users/:id/toggle-status` - āĻŦā§āϝāĻŦāĻšāĻžāϰāĻāĻžāϰ⧠āϏā§āĻā§āϝāĻžāĻāĻžāϏ
143- `POST /api/admin/broadcast` - āĻŦā§āϰāĻĄāĻāĻžāϏā§āĻ āύā§āĻāĻŋāĻĢāĻŋāĻā§āĻļāύ
144
145## đą āĻŦā§āϝāĻŦāĻšāĻžāϰā§āϰ āύāĻŋāϰā§āĻĻā§āĻļāύāĻž
170- **Input Validation**: āϏāĻŦ āĻāύāĻĒā§āĻ āϝāĻžāĻāĻžāĻ
171- **SQL Injection Protection**: Parameterized queries
172- **Rate Limiting**: API āĻāϞ āϏā§āĻŽāĻžāĻŦāĻĻā§āϧāϤāĻž
173- **CORS Protection**: āĻā§āϰāϏ-āĻ
āϰāĻŋāĻāĻŋāύ āύāĻŋāϰāĻžāĻĒāϤā§āϤāĻž
174
38 };
39
40 const response = await fetch('/api/admin/dashboard', { headers });
41 if (response.ok) {
42 const data = await response.json();
54 try {
55 const token = localStorage.getItem('adminToken');
56 const response = await fetch('/api/admin/users', {
57 headers: { 'Authorization': `Bearer ${token}` }
58 });
72 try {
73 const token = localStorage.getItem('adminToken');
74 const response = await fetch('/api/admin/transactions', {
75 headers: { 'Authorization': `Bearer ${token}` }
76 });
102 try {
103 const token = localStorage.getItem('adminToken');
104 const response = await fetch(`/api/admin/transactions/${transactionId}/status`, {
105 method: 'POST',
106 headers: {
127 try {
128 const token = localStorage.getItem('adminToken');
129 const response = await fetch(`/api/admin/users/${userId}/toggle-status`, {
130 method: 'POST',
131 headers: { 'Authorization': `Bearer ${token}` }
31
32 // Load tasks
33 const tasksResponse = await fetch('/api/tasks', { headers });
34 if (tasksResponse.ok) {
35 const tasksData = await tasksResponse.json();
38
39 // Load transactions
40 const transactionsResponse = await fetch('/api/payments/transactions', { headers });
41 if (transactionsResponse.ok) {
42 const transactionsData = await transactionsResponse.json();
45
46 // Load today's summary
47 const summaryResponse = await fetch('/api/tasks/today-summary', { headers });
48 if (summaryResponse.ok) {
49 const summaryData = await summaryResponse.json();
74 try {
75 const token = localStorage.getItem('authToken');
76 const response = await fetch('/api/tasks/complete', {
77 method: 'POST',
78 headers: {
49 if (isAdminLogin) {
50 // Admin login
51 const response = await fetch('/api/admin/login', {
52 method: 'POST',
53 headers: { 'Content-Type': 'application/json' },
67 } else if (isLogin) {
68 // User login
69 const response = await fetch('/api/auth/login', {
70 method: 'POST',
71 headers: { 'Content-Type': 'application/json' },
85 } else {
86 // User registration
87 const response = await fetch('/api/auth/register', {
88 method: 'POST',
89 headers: { 'Content-Type': 'application/json' },
31 if (adminToken) {
32 // Check admin token validity
33 const response = await fetch('/api/admin/dashboard', {
34 headers: {
35 'Authorization': `Bearer ${adminToken}`
47 if (token) {
48 // Verify user token
49 const response = await fetch('/api/auth/verify', {
50 method: 'POST',
51 headers: {
17await runMigrations();
18
19// API Routes
20app.route('/api/auth', auth);
21app.route('/api/tasks', tasks);
22app.route('/api/payments', payments);
23app.route('/api/admin', admin);
24
25// Serve static files
50 status: 'ok',
51 timestamp: new Date().toISOString(),
52 message: 'EarnBD API is running'
53 });
54});
78
79const getRandomVerse = async () => {
80 const ESV_API_TOKEN = Deno.env.get("ESV_API_TOKEN");
81 const reference = getRandomVerseReference();
82 const params = new URLSearchParams({
93 "indent-psalm-doxology": "0"
94 });
95 const url = `https://api.esv.org/v3/passage/text/?${params.toString()}`;
96 const resp = await fetch(url, {
97 headers: {
98 Authorization: `Token ${ESV_API_TOKEN}`,
99 },
100 });