init
This commit is contained in:
7
ace.js
Normal file
7
ace.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This file is auto-generated by the build process.
|
||||
* If you had any custom code inside this file, then
|
||||
* instead write it inside the "bin/console.js" file.
|
||||
*/
|
||||
|
||||
await import('./bin/console.js')
|
||||
53
adonisrc.js
Normal file
53
adonisrc.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { defineConfig } from '@adonisjs/core/app';
|
||||
export default defineConfig({
|
||||
experimental: {
|
||||
mergeMultipartFieldsAndFiles: true,
|
||||
shutdownInReverseOrder: true,
|
||||
},
|
||||
commands: [() => import('@adonisjs/core/commands')],
|
||||
providers: [
|
||||
() => import('@adonisjs/core/providers/app_provider'),
|
||||
() => import('@adonisjs/core/providers/hash_provider'),
|
||||
{
|
||||
file: () => import('@adonisjs/core/providers/repl_provider'),
|
||||
environment: ['repl', 'test'],
|
||||
},
|
||||
() => import('@adonisjs/core/providers/vinejs_provider'),
|
||||
() => import('@adonisjs/core/providers/edge_provider'),
|
||||
() => import('@adonisjs/session/session_provider'),
|
||||
() => import('@adonisjs/vite/vite_provider'),
|
||||
() => import('@adonisjs/shield/shield_provider'),
|
||||
() => import('@adonisjs/static/static_provider'),
|
||||
],
|
||||
preloads: [() => import('#start/routes'), () => import('#start/kernel')],
|
||||
tests: {
|
||||
suites: [
|
||||
{
|
||||
files: ['tests/unit/**/*.spec(.ts|.js)'],
|
||||
name: 'unit',
|
||||
timeout: 2000,
|
||||
},
|
||||
{
|
||||
files: ['tests/functional/**/*.spec(.ts|.js)'],
|
||||
name: 'functional',
|
||||
timeout: 30000,
|
||||
},
|
||||
],
|
||||
forceExit: false,
|
||||
},
|
||||
metaFiles: [
|
||||
{
|
||||
pattern: 'resources/views/**/*.edge',
|
||||
reloadServer: false,
|
||||
},
|
||||
{
|
||||
pattern: 'public/**',
|
||||
reloadServer: false,
|
||||
},
|
||||
],
|
||||
assetsBundler: false,
|
||||
hooks: {
|
||||
onBuildStarting: [() => import('@adonisjs/vite/build_hook')],
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=adonisrc.js.map
|
||||
1
adonisrc.js.map
Normal file
1
adonisrc.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"adonisrc.js","sourceRoot":"","sources":["../adonisrc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,eAAe,YAAY,CAAC;IAW1B,YAAY,EAAE;QACZ,4BAA4B,EAAE,IAAI;QAClC,sBAAsB,EAAE,IAAI;KAC7B;IAWD,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAWnD,SAAS,EAAE;QACT,GAAG,EAAE,CAAC,MAAM,CAAC,uCAAuC,CAAC;QACrD,GAAG,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC;QACtD;YACE,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC;YAC5D,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;SAC9B;QACD,GAAG,EAAE,CAAC,MAAM,CAAC,0CAA0C,CAAC;QACxD,GAAG,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC;QACtD,GAAG,EAAE,CAAC,MAAM,CAAC,oCAAoC,CAAC;QAClD,GAAG,EAAE,CAAC,MAAM,CAAC,8BAA8B,CAAC;QAC5C,GAAG,EAAE,CAAC,MAAM,CAAC,kCAAkC,CAAC;QAChD,GAAG,EAAE,CAAC,MAAM,CAAC,kCAAkC,CAAC;KACjD;IAUD,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAWxE,KAAK,EAAE;QACL,MAAM,EAAE;YACN;gBACE,KAAK,EAAE,CAAC,+BAA+B,CAAC;gBACxC,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,IAAI;aACd;YACD;gBACE,KAAK,EAAE,CAAC,qCAAqC,CAAC;gBAC9C,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,KAAK;aACf;SACF;QACD,SAAS,EAAE,KAAK;KACjB;IAED,SAAS,EAAE;QACT;YACE,OAAO,EAAE,2BAA2B;YACpC,YAAY,EAAE,KAAK;SACpB;QACD;YACE,OAAO,EAAE,WAAW;YACpB,YAAY,EAAE,KAAK;SACpB;KACF;IAED,aAAa,EAAE,KAAK;IACpB,KAAK,EAAE;QACL,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;KAC7D;CACF,CAAC,CAAA"}
|
||||
29
app/controllers/auth_controller.js
Normal file
29
app/controllers/auth_controller.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import env from '#start/env';
|
||||
export default class AuthController {
|
||||
async showLogin({ view, session, response }) {
|
||||
if (session.get('is_authenticated')) {
|
||||
return response.redirect().toPath('/');
|
||||
}
|
||||
return view.render('login');
|
||||
}
|
||||
async login({ request, session, response }) {
|
||||
const { username, password } = request.only(['username', 'password']);
|
||||
const validUsername = env.get('AUTH_USERNAME');
|
||||
const validPassword = env.get('AUTH_PASSWORD');
|
||||
if (username === validUsername && password === validPassword) {
|
||||
session.put('is_authenticated', true);
|
||||
session.put('username', username);
|
||||
const intendedUrl = session.get('intended_url', '/');
|
||||
session.forget('intended_url');
|
||||
return response.redirect().toPath(intendedUrl);
|
||||
}
|
||||
session.flash('errors', { form: 'Invalid username or password.' });
|
||||
session.flashOnly(['username']);
|
||||
return response.redirect().toPath('/login');
|
||||
}
|
||||
async logout({ session, response }) {
|
||||
session.clear();
|
||||
return response.redirect().toPath('/login');
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=auth_controller.js.map
|
||||
1
app/controllers/auth_controller.js.map
Normal file
1
app/controllers/auth_controller.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth_controller.js","sourceRoot":"","sources":["../../../app/controllers/auth_controller.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,YAAY,CAAA;AAE5B,MAAM,CAAC,OAAO,OAAO,cAAc;IAKjC,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAe;QACtD,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACpC,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACxC,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAQD,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAe;QACrD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA;QAErE,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;QAE9C,IAAI,QAAQ,KAAK,aAAa,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAA;YACrC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;YAEjC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;YACpD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YAC9B,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,+BAA+B,EAAE,CAAC,CAAA;QAElE,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;QAC/B,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC7C,CAAC;IAMD,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAe;QAC7C,OAAO,CAAC,KAAK,EAAE,CAAA;QACf,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC7C,CAAC;CACF"}
|
||||
50
app/controllers/media_controller.js
Normal file
50
app/controllers/media_controller.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { readdirSync, existsSync, statSync } from 'node:fs';
|
||||
import { extname, join } from 'node:path';
|
||||
const IMAGE_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
|
||||
const VIDEO_EXTENSIONS = new Set(['.mp4', '.mov', '.avi', '.webm']);
|
||||
function getMediaType(filename) {
|
||||
const ext = extname(filename).toLowerCase();
|
||||
if (IMAGE_EXTENSIONS.has(ext))
|
||||
return 'image';
|
||||
if (VIDEO_EXTENSIONS.has(ext))
|
||||
return 'video';
|
||||
return 'unknown';
|
||||
}
|
||||
export default class MediaController {
|
||||
async index({ view }) {
|
||||
const uploadsDir = app.publicPath('uploads');
|
||||
let files = [];
|
||||
try {
|
||||
const entries = readdirSync(uploadsDir, { withFileTypes: true });
|
||||
files = entries
|
||||
.filter((entry) => entry.isFile())
|
||||
.map((entry) => {
|
||||
const stat = statSync(join(uploadsDir, entry.name));
|
||||
return {
|
||||
filename: entry.name,
|
||||
url: `/uploads/${entry.name}`,
|
||||
type: getMediaType(entry.name),
|
||||
size: stat.size,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => b.filename.localeCompare(a.filename));
|
||||
}
|
||||
catch {
|
||||
files = [];
|
||||
}
|
||||
return view.render('dashboard', { files });
|
||||
}
|
||||
async serve({ params, response }) {
|
||||
const { filename } = params;
|
||||
if (!/^[\w\-. ]+$/.test(filename)) {
|
||||
return response.status(400).json({ error: 'Invalid filename.' });
|
||||
}
|
||||
const filePath = join(app.publicPath('uploads'), filename);
|
||||
if (!existsSync(filePath)) {
|
||||
return response.status(404).json({ error: 'Media not found', filename });
|
||||
}
|
||||
return response.download(filePath);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=media_controller.js.map
|
||||
1
app/controllers/media_controller.js.map
Normal file
1
app/controllers/media_controller.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"media_controller.js","sourceRoot":"","sources":["../../../app/controllers/media_controller.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAC5E,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAEnE,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;IAC3C,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IAC7C,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAA;IAC7C,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,CAAC,OAAO,OAAO,eAAe;IAKlC,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,EAAe;QAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAC5C,IAAI,KAAK,GAAgG,EAAE,CAAA;QAE3G,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;YAChE,KAAK,GAAG,OAAO;iBACZ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;iBACjC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACb,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;gBACnD,OAAO;oBACL,QAAQ,EAAE,KAAK,CAAC,IAAI;oBACpB,GAAG,EAAE,YAAY,KAAK,CAAC,IAAI,EAAE;oBAC7B,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC;oBAC9B,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAA;YACH,CAAC,CAAC;iBAED,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,KAAK,GAAG,EAAE,CAAA;QACZ,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5C,CAAC;IAMD,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAe;QAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;QAG3B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,OAAO,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAA;QAE1D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1E,CAAC;QAED,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACpC,CAAC;CACF"}
|
||||
40
app/controllers/upload_controller.js
Normal file
40
app/controllers/upload_controller.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import app from '@adonisjs/core/services/app';
|
||||
const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'mp4', 'mov', 'avi', 'webm'];
|
||||
const MAX_SIZE = '100mb';
|
||||
export default class UploadController {
|
||||
async store({ request, response }) {
|
||||
const file = request.file('file', {
|
||||
size: MAX_SIZE,
|
||||
extnames: ALLOWED_EXTENSIONS,
|
||||
});
|
||||
if (!file) {
|
||||
return response.badRequest({ success: false, message: 'No file provided.' });
|
||||
}
|
||||
if (!file.isValid) {
|
||||
return response.unprocessableEntity({
|
||||
success: false,
|
||||
message: file.errors[0]?.message ?? 'File validation failed.',
|
||||
errors: file.errors,
|
||||
});
|
||||
}
|
||||
const safeName = file.clientName.replace(/[^a-zA-Z0-9._-]/g, '_');
|
||||
const uniqueFilename = `${Date.now()}_${safeName}`;
|
||||
await file.move(app.publicPath('uploads'), {
|
||||
name: uniqueFilename,
|
||||
overwrite: false,
|
||||
});
|
||||
if (file.hasErrors) {
|
||||
return response.internalServerError({
|
||||
success: false,
|
||||
message: 'Could not save the file to disk.',
|
||||
errors: file.errors,
|
||||
});
|
||||
}
|
||||
return response.ok({
|
||||
success: true,
|
||||
filename: uniqueFilename,
|
||||
url: `/uploads/${uniqueFilename}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=upload_controller.js.map
|
||||
1
app/controllers/upload_controller.js.map
Normal file
1
app/controllers/upload_controller.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"upload_controller.js","sourceRoot":"","sources":["../../../app/controllers/upload_controller.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAE7C,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAC7F,MAAM,QAAQ,GAAG,OAAO,CAAA;AAExB,MAAM,CAAC,OAAO,OAAO,gBAAgB;IAMnC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAe;QAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;YAChC,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,kBAAkB;SAC7B,CAAC,CAAA;QAEF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAA;QAC9E,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,QAAQ,CAAC,mBAAmB,CAAC;gBAClC,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,yBAAyB;gBAC7D,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAA;QACJ,CAAC;QAGD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAA;QACjE,MAAM,cAAc,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAA;QAElD,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;YACzC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,KAAK;SACjB,CAAC,CAAA;QAEF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,QAAQ,CAAC,mBAAmB,CAAC;gBAClC,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,kCAAkC;gBAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC,EAAE,CAAC;YACjB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,cAAc;YACxB,GAAG,EAAE,YAAY,cAAc,EAAE;SAClC,CAAC,CAAA;IACJ,CAAC;CACF"}
|
||||
21
app/exceptions/handler.js
Normal file
21
app/exceptions/handler.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { ExceptionHandler } from '@adonisjs/core/http';
|
||||
export default class HttpExceptionHandler extends ExceptionHandler {
|
||||
debug = !app.inProduction;
|
||||
renderStatusPages = app.inProduction;
|
||||
statusPages = {
|
||||
'404': (error, { view }) => {
|
||||
return view.render('pages/errors/not_found', { error });
|
||||
},
|
||||
'500..599': (error, { view }) => {
|
||||
return view.render('pages/errors/server_error', { error });
|
||||
},
|
||||
};
|
||||
async handle(error, ctx) {
|
||||
return super.handle(error, ctx);
|
||||
}
|
||||
async report(error, ctx) {
|
||||
return super.report(error, ctx);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=handler.js.map
|
||||
1
app/exceptions/handler.js.map
Normal file
1
app/exceptions/handler.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../app/exceptions/handler.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAe,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAGnE,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,gBAAgB;IAKtD,KAAK,GAAG,CAAC,GAAG,CAAC,YAAY,CAAA;IAOzB,iBAAiB,GAAG,GAAG,CAAC,YAAY,CAAA;IAMpC,WAAW,GAAgD;QACnE,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACzB,OAAO,IAAI,CAAC,MAAM,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5D,CAAC;KACF,CAAA;IAMD,KAAK,CAAC,MAAM,CAAC,KAAc,EAAE,GAAgB;QAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACjC,CAAC;IAQD,KAAK,CAAC,MAAM,CAAC,KAAc,EAAE,GAAgB;QAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACjC,CAAC;CACF"}
|
||||
11
app/middleware/auth_middleware.js
Normal file
11
app/middleware/auth_middleware.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export default class AuthMiddleware {
|
||||
async handle({ session, response, request }, next) {
|
||||
const isAuthenticated = session.get('is_authenticated', false);
|
||||
if (!isAuthenticated) {
|
||||
session.put('intended_url', request.url());
|
||||
return response.redirect().toPath('/login');
|
||||
}
|
||||
await next();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=auth_middleware.js.map
|
||||
1
app/middleware/auth_middleware.js.map
Normal file
1
app/middleware/auth_middleware.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth_middleware.js","sourceRoot":"","sources":["../../../app/middleware/auth_middleware.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,OAAO,cAAc;IACjC,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAe,EAAE,IAAY;QACpE,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAA;QAE9D,IAAI,CAAC,eAAe,EAAE,CAAC;YAErB,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;YAC1C,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAC7C,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC;CACF"}
|
||||
10
app/middleware/container_bindings_middleware.js
Normal file
10
app/middleware/container_bindings_middleware.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Logger } from '@adonisjs/core/logger';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
export default class ContainerBindingsMiddleware {
|
||||
handle(ctx, next) {
|
||||
ctx.containerResolver.bindValue(HttpContext, ctx);
|
||||
ctx.containerResolver.bindValue(Logger, ctx.logger);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=container_bindings_middleware.js.map
|
||||
1
app/middleware/container_bindings_middleware.js.map
Normal file
1
app/middleware/container_bindings_middleware.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"container_bindings_middleware.js","sourceRoot":"","sources":["../../../app/middleware/container_bindings_middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAUjD,MAAM,CAAC,OAAO,OAAO,2BAA2B;IAC9C,MAAM,CAAC,GAAgB,EAAE,IAAY;QACnC,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;QACjD,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;QAEnD,OAAO,IAAI,EAAE,CAAA;IACf,CAAC;CACF"}
|
||||
24
bin/console.js
Normal file
24
bin/console.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'reflect-metadata';
|
||||
import { Ignitor, prettyPrintError } from '@adonisjs/core';
|
||||
const APP_ROOT = new URL('../', import.meta.url);
|
||||
const IMPORTER = (filePath) => {
|
||||
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
||||
return import(new URL(filePath, APP_ROOT).href);
|
||||
}
|
||||
return import(filePath);
|
||||
};
|
||||
new Ignitor(APP_ROOT, { importer: IMPORTER })
|
||||
.tap((app) => {
|
||||
app.booting(async () => {
|
||||
await import('#start/env');
|
||||
});
|
||||
app.listen('SIGTERM', () => app.terminate());
|
||||
app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate());
|
||||
})
|
||||
.ace()
|
||||
.handle(process.argv.splice(2))
|
||||
.catch((error) => {
|
||||
process.exitCode = 1;
|
||||
prettyPrintError(error);
|
||||
});
|
||||
//# sourceMappingURL=console.js.map
|
||||
1
bin/console.js.map
Normal file
1
bin/console.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"console.js","sourceRoot":"","sources":["../../bin/console.ts"],"names":[],"mappings":"AAaA,OAAO,kBAAkB,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAM1D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAMhD,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE;IACpC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,IAAI,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC1C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;IACX,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;QACrB,MAAM,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IACF,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5C,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;AACjE,CAAC,CAAC;KACD,GAAG,EAAE;KACL,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;KAC9B,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACf,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;IACpB,gBAAgB,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA"}
|
||||
24
bin/server.js
Normal file
24
bin/server.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'reflect-metadata';
|
||||
import { Ignitor, prettyPrintError } from '@adonisjs/core';
|
||||
const APP_ROOT = new URL('../', import.meta.url);
|
||||
const IMPORTER = (filePath) => {
|
||||
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
||||
return import(new URL(filePath, APP_ROOT).href);
|
||||
}
|
||||
return import(filePath);
|
||||
};
|
||||
new Ignitor(APP_ROOT, { importer: IMPORTER })
|
||||
.tap((app) => {
|
||||
app.booting(async () => {
|
||||
await import('#start/env');
|
||||
});
|
||||
app.listen('SIGTERM', () => app.terminate());
|
||||
app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate());
|
||||
})
|
||||
.httpServer()
|
||||
.start()
|
||||
.catch((error) => {
|
||||
process.exitCode = 1;
|
||||
prettyPrintError(error);
|
||||
});
|
||||
//# sourceMappingURL=server.js.map
|
||||
1
bin/server.js.map
Normal file
1
bin/server.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../bin/server.ts"],"names":[],"mappings":"AAWA,OAAO,kBAAkB,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAM1D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAMhD,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE;IACpC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,IAAI,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC1C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;IACX,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;QACrB,MAAM,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IACF,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5C,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;AACjE,CAAC,CAAC;KACD,UAAU,EAAE;KACZ,KAAK,EAAE;KACP,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACf,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;IACpB,gBAAgB,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA"}
|
||||
38
bin/test.js
Normal file
38
bin/test.js
Normal file
@@ -0,0 +1,38 @@
|
||||
process.env.NODE_ENV = 'test';
|
||||
import 'reflect-metadata';
|
||||
import { Ignitor, prettyPrintError } from '@adonisjs/core';
|
||||
import { configure, processCLIArgs, run } from '@japa/runner';
|
||||
const APP_ROOT = new URL('../', import.meta.url);
|
||||
const IMPORTER = (filePath) => {
|
||||
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
||||
return import(new URL(filePath, APP_ROOT).href);
|
||||
}
|
||||
return import(filePath);
|
||||
};
|
||||
new Ignitor(APP_ROOT, { importer: IMPORTER })
|
||||
.tap((app) => {
|
||||
app.booting(async () => {
|
||||
await import('#start/env');
|
||||
});
|
||||
app.listen('SIGTERM', () => app.terminate());
|
||||
app.listenIf(app.managedByPm2, 'SIGINT', () => app.terminate());
|
||||
})
|
||||
.testRunner()
|
||||
.configure(async (app) => {
|
||||
const { runnerHooks, ...config } = await import('../tests/bootstrap.js');
|
||||
processCLIArgs(process.argv.splice(2));
|
||||
configure({
|
||||
...app.rcFile.tests,
|
||||
...config,
|
||||
...{
|
||||
setup: runnerHooks.setup,
|
||||
teardown: runnerHooks.teardown.concat([() => app.terminate()]),
|
||||
},
|
||||
});
|
||||
})
|
||||
.run(() => run())
|
||||
.catch((error) => {
|
||||
process.exitCode = 1;
|
||||
prettyPrintError(error);
|
||||
});
|
||||
//# sourceMappingURL=test.js.map
|
||||
1
bin/test.js.map
Normal file
1
bin/test.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../bin/test.ts"],"names":[],"mappings":"AAYA,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAA;AAE7B,OAAO,kBAAkB,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAM7D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAMhD,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,EAAE;IACpC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,IAAI,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC1C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;IACX,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;QACrB,MAAM,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IACF,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5C,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAA;AACjE,CAAC,CAAC;KACD,UAAU,EAAE;KACZ,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACvB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAExE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,SAAS,CAAC;QACR,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK;QACnB,GAAG,MAAM;QACT,GAAG;YACD,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;SAC/D;KACF,CAAC,CAAA;AACJ,CAAC,CAAC;KACD,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;KAChB,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACf,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;IACpB,gBAAgB,CAAC,KAAK,CAAC,CAAA;AACzB,CAAC,CAAC,CAAA"}
|
||||
19
config/app.js
Normal file
19
config/app.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import env from '#start/env';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { Secret } from '@adonisjs/core/helpers';
|
||||
import { defineConfig } from '@adonisjs/core/http';
|
||||
export const appKey = new Secret(env.get('APP_KEY'));
|
||||
export const http = defineConfig({
|
||||
generateRequestId: true,
|
||||
allowMethodSpoofing: false,
|
||||
useAsyncLocalStorage: false,
|
||||
cookie: {
|
||||
domain: '',
|
||||
path: '/',
|
||||
maxAge: '2h',
|
||||
httpOnly: true,
|
||||
secure: app.inProduction,
|
||||
sameSite: 'lax',
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=app.js.map
|
||||
1
config/app.js.map
Normal file
1
config/app.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../config/app.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,YAAY,CAAA;AAC5B,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AASlD,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAA;AAKpD,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC;IAC/B,iBAAiB,EAAE,IAAI;IACvB,mBAAmB,EAAE,KAAK;IAM1B,oBAAoB,EAAE,KAAK;IAM3B,MAAM,EAAE;QACN,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,GAAG;QACT,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,YAAY;QACxB,QAAQ,EAAE,KAAK;KAChB;CACF,CAAC,CAAA"}
|
||||
26
config/bodyparser.js
Normal file
26
config/bodyparser.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineConfig } from '@adonisjs/core/bodyparser';
|
||||
const bodyParserConfig = defineConfig({
|
||||
allowedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
|
||||
form: {
|
||||
convertEmptyStringsToNull: true,
|
||||
types: ['application/x-www-form-urlencoded'],
|
||||
},
|
||||
json: {
|
||||
convertEmptyStringsToNull: true,
|
||||
types: [
|
||||
'application/json',
|
||||
'application/json-patch+json',
|
||||
'application/vnd.api+json',
|
||||
'application/csp-report',
|
||||
],
|
||||
},
|
||||
multipart: {
|
||||
autoProcess: true,
|
||||
convertEmptyStringsToNull: true,
|
||||
processManually: [],
|
||||
limit: '100mb',
|
||||
types: ['multipart/form-data'],
|
||||
},
|
||||
});
|
||||
export default bodyParserConfig;
|
||||
//# sourceMappingURL=bodyparser.js.map
|
||||
1
config/bodyparser.js.map
Normal file
1
config/bodyparser.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"bodyparser.js","sourceRoot":"","sources":["../../config/bodyparser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAExD,MAAM,gBAAgB,GAAG,YAAY,CAAC;IAKpC,cAAc,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;IAMlD,IAAI,EAAE;QACJ,yBAAyB,EAAE,IAAI;QAC/B,KAAK,EAAE,CAAC,mCAAmC,CAAC;KAC7C;IAKD,IAAI,EAAE;QACJ,yBAAyB,EAAE,IAAI;QAC/B,KAAK,EAAE;YACL,kBAAkB;YAClB,6BAA6B;YAC7B,0BAA0B;YAC1B,wBAAwB;SACzB;KACF;IAMD,SAAS,EAAE;QAMT,WAAW,EAAE,IAAI;QACjB,yBAAyB,EAAE,IAAI;QAC/B,eAAe,EAAE,EAAE;QAMnB,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,CAAC,qBAAqB,CAAC;KAC/B;CACF,CAAC,CAAA;AAEF,eAAe,gBAAgB,CAAA"}
|
||||
14
config/hash.js
Normal file
14
config/hash.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig, drivers } from '@adonisjs/core/hash';
|
||||
const hashConfig = defineConfig({
|
||||
default: 'scrypt',
|
||||
list: {
|
||||
scrypt: drivers.scrypt({
|
||||
cost: 16384,
|
||||
blockSize: 8,
|
||||
parallelization: 1,
|
||||
maxMemory: 33554432,
|
||||
}),
|
||||
},
|
||||
});
|
||||
export default hashConfig;
|
||||
//# sourceMappingURL=hash.js.map
|
||||
1
config/hash.js.map
Normal file
1
config/hash.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../config/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE3D,MAAM,UAAU,GAAG,YAAY,CAAC;IAC9B,OAAO,EAAE,QAAQ;IAEjB,IAAI,EAAE;QACJ,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;YACrB,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,CAAC;YACZ,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,QAAQ;SACpB,CAAC;KACH;CACF,CAAC,CAAA;AAEF,eAAe,UAAU,CAAA"}
|
||||
21
config/logger.js
Normal file
21
config/logger.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import env from '#start/env';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { defineConfig, targets } from '@adonisjs/core/logger';
|
||||
const loggerConfig = defineConfig({
|
||||
default: 'app',
|
||||
loggers: {
|
||||
app: {
|
||||
enabled: true,
|
||||
name: env.get('APP_NAME'),
|
||||
level: env.get('LOG_LEVEL'),
|
||||
transport: {
|
||||
targets: targets()
|
||||
.pushIf(!app.inProduction, targets.pretty())
|
||||
.pushIf(app.inProduction, targets.file({ destination: 1 }))
|
||||
.toArray(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
export default loggerConfig;
|
||||
//# sourceMappingURL=logger.js.map
|
||||
1
config/logger.js.map
Normal file
1
config/logger.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../config/logger.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,YAAY,CAAA;AAC5B,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAE7D,MAAM,YAAY,GAAG,YAAY,CAAC;IAChC,OAAO,EAAE,KAAK;IAMd,OAAO,EAAE;QACP,GAAG,EAAE;YACH,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;YACzB,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;YAC3B,SAAS,EAAE;gBACT,OAAO,EAAE,OAAO,EAAE;qBACf,MAAM,CAAC,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;qBAC3C,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;qBAC1D,OAAO,EAAE;aACb;SACF;KACF;CACF,CAAC,CAAA;AAEF,eAAe,YAAY,CAAA"}
|
||||
21
config/session.js
Normal file
21
config/session.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import env from '#start/env';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { defineConfig, stores } from '@adonisjs/session';
|
||||
const sessionConfig = defineConfig({
|
||||
enabled: true,
|
||||
cookieName: 'adonis-session',
|
||||
clearWithBrowser: false,
|
||||
age: '2h',
|
||||
cookie: {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
secure: app.inProduction,
|
||||
sameSite: 'lax',
|
||||
},
|
||||
store: env.get('SESSION_DRIVER'),
|
||||
stores: {
|
||||
cookie: stores.cookie(),
|
||||
},
|
||||
});
|
||||
export default sessionConfig;
|
||||
//# sourceMappingURL=session.js.map
|
||||
1
config/session.js.map
Normal file
1
config/session.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../config/session.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,YAAY,CAAA;AAC5B,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,aAAa,GAAG,YAAY,CAAC;IACjC,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,gBAAgB;IAM5B,gBAAgB,EAAE,KAAK;IAMvB,GAAG,EAAE,IAAI;IAMT,MAAM,EAAE;QACN,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,YAAY;QACxB,QAAQ,EAAE,KAAK;KAChB;IAOD,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAMhC,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;KACxB;CACF,CAAC,CAAA;AAEF,eAAe,aAAa,CAAA"}
|
||||
27
config/shield.js
Normal file
27
config/shield.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from '@adonisjs/shield';
|
||||
const shieldConfig = defineConfig({
|
||||
csp: {
|
||||
enabled: false,
|
||||
directives: {},
|
||||
reportOnly: false,
|
||||
},
|
||||
csrf: {
|
||||
enabled: true,
|
||||
exceptRoutes: [],
|
||||
enableXsrfCookie: false,
|
||||
methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
|
||||
},
|
||||
xFrame: {
|
||||
enabled: true,
|
||||
action: 'DENY',
|
||||
},
|
||||
hsts: {
|
||||
enabled: true,
|
||||
maxAge: '180 days',
|
||||
},
|
||||
contentTypeSniffing: {
|
||||
enabled: true,
|
||||
},
|
||||
});
|
||||
export default shieldConfig;
|
||||
//# sourceMappingURL=shield.js.map
|
||||
1
config/shield.js.map
Normal file
1
config/shield.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"shield.js","sourceRoot":"","sources":["../../config/shield.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,MAAM,YAAY,GAAG,YAAY,CAAC;IAKhC,GAAG,EAAE;QACH,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,EAAE;QACd,UAAU,EAAE,KAAK;KAClB;IAMD,IAAI,EAAE;QACJ,OAAO,EAAE,IAAI;QACb,YAAY,EAAE,EAAE;QAChB,gBAAgB,EAAE,KAAK;QACvB,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;KAC5C;IAMD,MAAM,EAAE;QACN,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,MAAM;KACf;IAKD,IAAI,EAAE;QACJ,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,UAAU;KACnB;IAMD,mBAAmB,EAAE;QACnB,OAAO,EAAE,IAAI;KACd;CACF,CAAC,CAAA;AAEF,eAAe,YAAY,CAAA"}
|
||||
9
config/static.js
Normal file
9
config/static.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from '@adonisjs/static';
|
||||
const staticServerConfig = defineConfig({
|
||||
enabled: true,
|
||||
etag: true,
|
||||
lastModified: true,
|
||||
dotFiles: 'ignore',
|
||||
});
|
||||
export default staticServerConfig;
|
||||
//# sourceMappingURL=static.js.map
|
||||
1
config/static.js.map
Normal file
1
config/static.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"static.js","sourceRoot":"","sources":["../../config/static.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAS/C,MAAM,kBAAkB,GAAG,YAAY,CAAC;IACtC,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,QAAQ;CACnB,CAAC,CAAA;AAEF,eAAe,kBAAkB,CAAA"}
|
||||
11
config/vite.js
Normal file
11
config/vite.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from '@adonisjs/vite';
|
||||
const viteBackendConfig = defineConfig({
|
||||
buildDirectory: 'public/assets',
|
||||
manifestFile: 'public/assets/.vite/manifest.json',
|
||||
assetsUrl: '/assets',
|
||||
scriptAttributes: {
|
||||
defer: true,
|
||||
},
|
||||
});
|
||||
export default viteBackendConfig;
|
||||
//# sourceMappingURL=vite.js.map
|
||||
1
config/vite.js.map
Normal file
1
config/vite.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../config/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,iBAAiB,GAAG,YAAY,CAAC;IAMrC,cAAc,EAAE,eAAe;IAM/B,YAAY,EAAE,mCAAmC;IAMjD,SAAS,EAAE,SAAS;IAEpB,gBAAgB,EAAE;QAChB,KAAK,EAAE,IAAI;KACZ;CACF,CAAC,CAAA;AAEF,eAAe,iBAAiB,CAAA"}
|
||||
28
gitignore
Normal file
28
gitignore
Normal file
@@ -0,0 +1,28 @@
|
||||
# Dependencies and AdonisJS build
|
||||
node_modules
|
||||
build
|
||||
tmp
|
||||
|
||||
# Secrets
|
||||
.env
|
||||
.env.local
|
||||
.env.production.local
|
||||
.env.development.local
|
||||
|
||||
# Frontend assets compiled code
|
||||
public/assets
|
||||
|
||||
# Uploaded media files
|
||||
public/uploads
|
||||
|
||||
# Build tools specific
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Editors specific
|
||||
.fleet
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Platform specific
|
||||
.DS_Store
|
||||
8999
package-lock.json
generated
Normal file
8999
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
71
package.json
Normal file
71
package.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "adonisjs-web-stater-kit",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"start": "node bin/server.js",
|
||||
"build": "node ace build",
|
||||
"dev": "node ace serve --hmr",
|
||||
"test": "node ace test",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"imports": {
|
||||
"#controllers/*": "./app/controllers/*.js",
|
||||
"#exceptions/*": "./app/exceptions/*.js",
|
||||
"#models/*": "./app/models/*.js",
|
||||
"#mails/*": "./app/mails/*.js",
|
||||
"#services/*": "./app/services/*.js",
|
||||
"#listeners/*": "./app/listeners/*.js",
|
||||
"#events/*": "./app/events/*.js",
|
||||
"#middleware/*": "./app/middleware/*.js",
|
||||
"#validators/*": "./app/validators/*.js",
|
||||
"#providers/*": "./providers/*.js",
|
||||
"#policies/*": "./app/policies/*.js",
|
||||
"#abilities/*": "./app/abilities/*.js",
|
||||
"#database/*": "./database/*.js",
|
||||
"#tests/*": "./tests/*.js",
|
||||
"#start/*": "./start/*.js",
|
||||
"#config/*": "./config/*.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adonisjs/assembler": "^7.8.2",
|
||||
"@adonisjs/eslint-config": "^2.0.0",
|
||||
"@adonisjs/prettier-config": "^1.4.4",
|
||||
"@adonisjs/tsconfig": "^1.4.0",
|
||||
"@japa/assert": "^4.0.1",
|
||||
"@japa/plugin-adonisjs": "^4.0.0",
|
||||
"@japa/runner": "^4.2.0",
|
||||
"@swc/core": "1.11.24",
|
||||
"@types/node": "^22.15.18",
|
||||
"eslint": "^9.26.0",
|
||||
"hot-hook": "^0.4.0",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-node-maintained": "^10.9.5",
|
||||
"typescript": "~5.8",
|
||||
"vite": "^6.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adonisjs/auth": "^9.4.0",
|
||||
"@adonisjs/core": "^6.18.0",
|
||||
"@adonisjs/lucid": "^21.6.1",
|
||||
"@adonisjs/session": "^7.5.1",
|
||||
"@adonisjs/shield": "^8.2.0",
|
||||
"@adonisjs/static": "^1.1.1",
|
||||
"@adonisjs/vite": "^4.0.0",
|
||||
"@vinejs/vine": "^3.0.1",
|
||||
"edge.js": "^6.2.1",
|
||||
"reflect-metadata": "^0.2.2"
|
||||
},
|
||||
"hotHook": {
|
||||
"boundaries": [
|
||||
"./app/controllers/**/*.ts",
|
||||
"./app/middleware/*.ts"
|
||||
]
|
||||
},
|
||||
"prettier": "@adonisjs/prettier-config"
|
||||
}
|
||||
13
public/assets/.vite/manifest.json
Normal file
13
public/assets/.vite/manifest.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"resources/css/app.css": {
|
||||
"file": "app-V1pZY7xQ.css",
|
||||
"src": "resources/css/app.css",
|
||||
"isEntry": true
|
||||
},
|
||||
"resources/js/app.js": {
|
||||
"file": "app-C3S-8paM.js",
|
||||
"name": "app",
|
||||
"src": "resources/js/app.js",
|
||||
"isEntry": true
|
||||
}
|
||||
}
|
||||
1
public/assets/app-C3S-8paM.js
Normal file
1
public/assets/app-C3S-8paM.js
Normal file
@@ -0,0 +1 @@
|
||||
console.log("Hello World");
|
||||
1
public/assets/app-V1pZY7xQ.css
Normal file
1
public/assets/app-V1pZY7xQ.css
Normal file
@@ -0,0 +1 @@
|
||||
*{margin:0;padding:0}html,body{height:100%;width:100%}
|
||||
BIN
public/uploads/1777542211622_amonus.png
Normal file
BIN
public/uploads/1777542211622_amonus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
43
resources/views/components/layouts/main.edge
Normal file
43
resources/views/components/layouts/main.edge
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ title ?? 'Imago Vault' }}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
@if($slots.head)
|
||||
{{{ await $slots.head() }}}
|
||||
@end
|
||||
</head>
|
||||
<body class="bg-gray-950 text-gray-100 min-h-screen">
|
||||
|
||||
{{-- Flash: success --}}
|
||||
@if(flashMessages.has('success'))
|
||||
<div id="flash-success"
|
||||
class="fixed top-4 right-4 z-50 bg-green-600 text-white px-6 py-3 rounded-lg shadow-lg text-sm font-medium pointer-events-none">
|
||||
{{ flashMessages.get('success') }}
|
||||
</div>
|
||||
@end
|
||||
|
||||
{{-- Flash: error --}}
|
||||
@if(flashMessages.has('error'))
|
||||
<div id="flash-error"
|
||||
class="fixed top-4 right-4 z-50 bg-red-600 text-white px-6 py-3 rounded-lg shadow-lg text-sm font-medium pointer-events-none">
|
||||
{{ flashMessages.get('error') }}
|
||||
</div>
|
||||
@end
|
||||
|
||||
{{{ await $slots.main() }}}
|
||||
|
||||
<script>
|
||||
// Auto-dismiss flash messages after 4 s
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('[id^="flash-"]').forEach(el => {
|
||||
el.style.transition = 'opacity 0.5s'
|
||||
el.style.opacity = '0'
|
||||
setTimeout(() => el.remove(), 500)
|
||||
})
|
||||
}, 4000)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
340
resources/views/dashboard.edge
Normal file
340
resources/views/dashboard.edge
Normal file
@@ -0,0 +1,340 @@
|
||||
@layouts.main({ title: 'Dashboard — Imago Vault' })
|
||||
@slot('main')
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
|
||||
{{-- ── Header ──────────────────────────────────────────────────────── --}}
|
||||
<header class="flex items-center justify-between mb-8">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-white">Media Library</h1>
|
||||
<p class="text-gray-400 text-sm mt-1">
|
||||
{{ files.length }} file{{ files.length !== 1 ? 's' : '' }} stored
|
||||
</p>
|
||||
</div>
|
||||
<a href="/logout"
|
||||
class="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 text-sm rounded-lg
|
||||
transition border border-gray-700">
|
||||
Logout
|
||||
</a>
|
||||
</header>
|
||||
|
||||
{{-- ── Upload zone ─────────────────────────────────────────────────── --}}
|
||||
<section class="mb-10">
|
||||
|
||||
<div id="drop-zone"
|
||||
class="relative border-2 border-dashed border-gray-700 rounded-2xl p-10
|
||||
text-center cursor-pointer transition-all duration-200
|
||||
hover:border-indigo-500 hover:bg-indigo-950/20">
|
||||
|
||||
{{-- Default hint (hidden once a file is selected) --}}
|
||||
<div id="drop-hint" class="flex flex-col items-center gap-3 pointer-events-none">
|
||||
<svg class="w-12 h-12 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
|
||||
</svg>
|
||||
<p class="text-gray-400 text-sm">
|
||||
Drag & drop a file here, or
|
||||
<label for="file-input"
|
||||
class="text-indigo-400 hover:text-indigo-300 cursor-pointer underline underline-offset-2">
|
||||
click to browse
|
||||
</label>
|
||||
</p>
|
||||
<p class="text-gray-600 text-xs">
|
||||
Images (JPG, PNG, GIF, WebP) · Videos (MP4, MOV, AVI, WebM) · Max 100 MB
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{{-- Preview area (shown after file selection) --}}
|
||||
<div id="preview-container" class="hidden mt-2">
|
||||
<img id="image-preview"
|
||||
class="hidden max-h-64 mx-auto rounded-lg object-contain"
|
||||
alt="Preview" />
|
||||
<video id="video-preview"
|
||||
class="hidden max-h-64 mx-auto rounded-lg"
|
||||
controls muted playsinline></video>
|
||||
<p id="preview-filename" class="text-gray-300 text-sm mt-3 font-medium"></p>
|
||||
<p id="preview-size" class="text-gray-500 text-xs mt-1"></p>
|
||||
</div>
|
||||
|
||||
{{-- Invisible file input covers the whole zone --}}
|
||||
<input type="file"
|
||||
id="file-input"
|
||||
accept="image/jpeg,image/png,image/gif,image/webp,video/mp4,video/quicktime,video/x-msvideo,video/webm"
|
||||
class="absolute inset-0 opacity-0 cursor-pointer w-full h-full" />
|
||||
</div>
|
||||
|
||||
{{-- Progress bar (shown during upload) --}}
|
||||
<div id="progress-wrapper" class="hidden mt-4">
|
||||
<div class="flex items-center justify-between text-sm mb-2">
|
||||
<span id="progress-label" class="text-gray-400">Uploading…</span>
|
||||
<span id="progress-percent" class="text-indigo-400 font-mono font-medium">0%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-800 rounded-full h-2 overflow-hidden">
|
||||
<div id="progress-bar"
|
||||
class="h-full bg-indigo-500 rounded-full transition-all duration-100"
|
||||
style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Action buttons (shown after file selection) --}}
|
||||
<div id="upload-actions" class="hidden flex gap-3 mt-4">
|
||||
<button id="upload-btn"
|
||||
class="px-6 py-2.5 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold
|
||||
rounded-lg text-sm transition focus:outline-none focus:ring-2 focus:ring-indigo-400">
|
||||
Upload File
|
||||
</button>
|
||||
<button id="cancel-btn"
|
||||
class="px-6 py-2.5 bg-gray-800 hover:bg-gray-700 text-gray-300
|
||||
rounded-lg text-sm transition border border-gray-700">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- Inline result message --}}
|
||||
<div id="upload-result" class="hidden mt-4 px-4 py-3 rounded-lg text-sm font-medium"></div>
|
||||
|
||||
</section>
|
||||
|
||||
{{-- ── Gallery ──────────────────────────────────────────────────────── --}}
|
||||
<section>
|
||||
<h2 class="text-lg font-semibold text-gray-200 mb-4">Uploaded Files</h2>
|
||||
|
||||
@if(files.length === 0)
|
||||
<div class="text-center py-20 text-gray-600">
|
||||
<svg class="w-16 h-16 mx-auto mb-4 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1"
|
||||
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14
|
||||
m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
<p>No files uploaded yet. Drop one above to get started.</p>
|
||||
</div>
|
||||
@else
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
@each(file in files)
|
||||
<div class="bg-gray-900 rounded-xl overflow-hidden border border-gray-800
|
||||
hover:border-gray-700 transition group">
|
||||
|
||||
{{-- Media preview --}}
|
||||
@if(file.type === 'image')
|
||||
<div class="aspect-video bg-gray-950 overflow-hidden">
|
||||
<img src="{{ file.url }}"
|
||||
alt="{{ file.filename }}"
|
||||
loading="lazy"
|
||||
class="w-full h-full object-cover group-hover:scale-105 transition duration-300" />
|
||||
</div>
|
||||
@elseif(file.type === 'video')
|
||||
<div class="aspect-video bg-black">
|
||||
<video src="{{ file.url }}"
|
||||
class="w-full h-full object-contain"
|
||||
controls preload="metadata" muted playsinline></video>
|
||||
</div>
|
||||
@else
|
||||
<div class="aspect-video bg-gray-950 flex items-center justify-center">
|
||||
<svg class="w-12 h-12 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1"
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1
|
||||
0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
@end
|
||||
|
||||
{{-- Info row --}}
|
||||
<div class="p-3">
|
||||
<p class="text-gray-300 text-xs font-medium truncate mb-2"
|
||||
title="{{ file.filename }}">
|
||||
{{ file.filename }}
|
||||
</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<button onclick="copyUrl('{{ file.url }}')"
|
||||
class="flex-1 px-3 py-1.5 bg-gray-800 hover:bg-gray-700 text-gray-300
|
||||
text-xs rounded-lg transition flex items-center gap-1.5 justify-center">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2
|
||||
m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
Copy URL
|
||||
</button>
|
||||
<a href="/api/media/{{ file.filename }}" target="_blank" rel="noopener"
|
||||
class="px-3 py-1.5 bg-indigo-900/40 hover:bg-indigo-900/60 text-indigo-400
|
||||
text-xs rounded-lg transition">
|
||||
Open
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@end
|
||||
</div>
|
||||
@end
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{{-- ── JavaScript ───────────────────────────────────────────────────── --}}
|
||||
<script>
|
||||
// CSRF token injected server-side — sent as a header on the XHR upload request
|
||||
const CSRF_TOKEN = '{{ csrfToken }}'
|
||||
|
||||
const dropZone = document.getElementById('drop-zone')
|
||||
const fileInput = document.getElementById('file-input')
|
||||
const dropHint = document.getElementById('drop-hint')
|
||||
const previewCont = document.getElementById('preview-container')
|
||||
const imagePreview = document.getElementById('image-preview')
|
||||
const videoPreview = document.getElementById('video-preview')
|
||||
const previewName = document.getElementById('preview-filename')
|
||||
const previewSize = document.getElementById('preview-size')
|
||||
const uploadActions = document.getElementById('upload-actions')
|
||||
const uploadBtn = document.getElementById('upload-btn')
|
||||
const cancelBtn = document.getElementById('cancel-btn')
|
||||
const progressWrap = document.getElementById('progress-wrapper')
|
||||
const progressBar = document.getElementById('progress-bar')
|
||||
const progressPct = document.getElementById('progress-percent')
|
||||
const uploadResult = document.getElementById('upload-result')
|
||||
|
||||
let selectedFile = null
|
||||
|
||||
// ── Drag & drop ─────────────────────────────────────────────────────
|
||||
dropZone.addEventListener('dragover', (e) => {
|
||||
e.preventDefault()
|
||||
dropZone.classList.add('border-indigo-500', 'bg-indigo-950/20')
|
||||
})
|
||||
dropZone.addEventListener('dragleave', () => {
|
||||
dropZone.classList.remove('border-indigo-500', 'bg-indigo-950/20')
|
||||
})
|
||||
dropZone.addEventListener('drop', (e) => {
|
||||
e.preventDefault()
|
||||
dropZone.classList.remove('border-indigo-500', 'bg-indigo-950/20')
|
||||
const file = e.dataTransfer.files[0]
|
||||
if (file) handleFileSelected(file)
|
||||
})
|
||||
|
||||
fileInput.addEventListener('change', () => {
|
||||
if (fileInput.files[0]) handleFileSelected(fileInput.files[0])
|
||||
})
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (bytes < 1024) return bytes + ' B'
|
||||
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
|
||||
return (bytes / 1048576).toFixed(1) + ' MB'
|
||||
}
|
||||
|
||||
function handleFileSelected(file) {
|
||||
selectedFile = file
|
||||
imagePreview.classList.add('hidden')
|
||||
videoPreview.classList.add('hidden')
|
||||
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
imagePreview.src = e.target.result
|
||||
imagePreview.classList.remove('hidden')
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
} else if (file.type.startsWith('video/')) {
|
||||
videoPreview.src = URL.createObjectURL(file)
|
||||
videoPreview.classList.remove('hidden')
|
||||
}
|
||||
|
||||
previewName.textContent = file.name
|
||||
previewSize.textContent = formatBytes(file.size)
|
||||
dropHint.classList.add('hidden')
|
||||
previewCont.classList.remove('hidden')
|
||||
uploadActions.classList.remove('hidden')
|
||||
uploadResult.classList.add('hidden')
|
||||
resetProgress()
|
||||
}
|
||||
|
||||
function resetProgress() {
|
||||
progressWrap.classList.add('hidden')
|
||||
progressBar.style.width = '0%'
|
||||
progressPct.textContent = '0%'
|
||||
}
|
||||
|
||||
cancelBtn.addEventListener('click', () => {
|
||||
selectedFile = null
|
||||
fileInput.value = ''
|
||||
dropHint.classList.remove('hidden')
|
||||
previewCont.classList.add('hidden')
|
||||
uploadActions.classList.add('hidden')
|
||||
uploadResult.classList.add('hidden')
|
||||
resetProgress()
|
||||
if (videoPreview.src) {
|
||||
URL.revokeObjectURL(videoPreview.src)
|
||||
videoPreview.src = ''
|
||||
}
|
||||
})
|
||||
|
||||
uploadBtn.addEventListener('click', () => {
|
||||
if (!selectedFile) return
|
||||
doUpload(selectedFile)
|
||||
})
|
||||
|
||||
function doUpload(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const xhr = new XMLHttpRequest()
|
||||
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.lengthComputable) {
|
||||
const pct = Math.round((e.loaded / e.total) * 100)
|
||||
progressBar.style.width = pct + '%'
|
||||
progressPct.textContent = pct + '%'
|
||||
}
|
||||
})
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
let data = {}
|
||||
try { data = JSON.parse(xhr.responseText) } catch {}
|
||||
|
||||
progressWrap.classList.add('hidden')
|
||||
uploadActions.classList.add('hidden')
|
||||
uploadResult.classList.remove('hidden')
|
||||
|
||||
if (xhr.status === 200 && data.success) {
|
||||
uploadResult.className =
|
||||
'mt-4 px-4 py-3 rounded-lg text-sm font-medium bg-green-900/40 border border-green-700 text-green-300'
|
||||
uploadResult.textContent = 'Uploaded: ' + data.filename
|
||||
// Reload the gallery so the new file appears
|
||||
setTimeout(() => window.location.reload(), 1200)
|
||||
} else {
|
||||
uploadResult.className =
|
||||
'mt-4 px-4 py-3 rounded-lg text-sm font-medium bg-red-900/40 border border-red-700 text-red-300'
|
||||
uploadResult.textContent = data.message || 'Upload failed. Please try again.'
|
||||
uploadBtn.disabled = false
|
||||
}
|
||||
})
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
progressWrap.classList.add('hidden')
|
||||
uploadResult.classList.remove('hidden')
|
||||
uploadResult.className =
|
||||
'mt-4 px-4 py-3 rounded-lg text-sm font-medium bg-red-900/40 border border-red-700 text-red-300'
|
||||
uploadResult.textContent = 'Network error. Please check your connection and try again.'
|
||||
uploadBtn.disabled = false
|
||||
})
|
||||
|
||||
xhr.open('POST', '/upload')
|
||||
xhr.setRequestHeader('X-CSRF-TOKEN', CSRF_TOKEN)
|
||||
uploadBtn.disabled = true
|
||||
previewCont.classList.add('hidden')
|
||||
progressWrap.classList.remove('hidden')
|
||||
resetProgress()
|
||||
xhr.send(formData)
|
||||
}
|
||||
|
||||
// ── Copy URL to clipboard ─────────────────────────────────────────
|
||||
function copyUrl(url) {
|
||||
const fullUrl = window.location.origin + url
|
||||
navigator.clipboard.writeText(fullUrl).then(() => {
|
||||
const btn = event.currentTarget
|
||||
const orig = btn.innerHTML
|
||||
btn.textContent = 'Copied!'
|
||||
btn.classList.add('text-green-400')
|
||||
setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('text-green-400') }, 1500)
|
||||
}).catch(() => {
|
||||
prompt('Copy this URL:', window.location.origin + url)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@endslot
|
||||
@end
|
||||
77
resources/views/login.edge
Normal file
77
resources/views/login.edge
Normal file
@@ -0,0 +1,77 @@
|
||||
@layouts.main({ title: 'Sign In — Imago Vault' })
|
||||
@slot('main')
|
||||
<div class="min-h-screen flex items-center justify-center px-4">
|
||||
<div class="w-full max-w-md">
|
||||
|
||||
{{-- Logo / heading --}}
|
||||
<div class="text-center mb-8">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 bg-indigo-600 rounded-2xl mb-4 shadow-lg">
|
||||
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-white">Imago Vault</h1>
|
||||
<p class="text-gray-400 text-sm mt-1">Sign in to manage your media files</p>
|
||||
</div>
|
||||
|
||||
{{-- Credential error message --}}
|
||||
@if(flashMessages.has('errors'))
|
||||
<div class="bg-red-900/40 border border-red-700 text-red-300 px-4 py-3 rounded-lg mb-6 text-sm">
|
||||
{{ flashMessages.get('errors').form ?? 'An error occurred.' }}
|
||||
</div>
|
||||
@end
|
||||
|
||||
{{-- Login form --}}
|
||||
<form method="POST" action="/login"
|
||||
class="bg-gray-900 rounded-2xl p-8 shadow-2xl border border-gray-800">
|
||||
{{ csrfField() }}
|
||||
|
||||
<div class="mb-5">
|
||||
<label for="username" class="block text-sm font-medium text-gray-300 mb-2">
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
value="{{ flashMessages.get('username') ?? '' }}"
|
||||
required
|
||||
autocomplete="username"
|
||||
class="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg text-white
|
||||
placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500
|
||||
focus:border-transparent transition"
|
||||
placeholder="admin"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
<label for="password" class="block text-sm font-medium text-gray-300 mb-2">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
class="w-full px-4 py-3 bg-gray-800 border border-gray-700 rounded-lg text-white
|
||||
placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500
|
||||
focus:border-transparent transition"
|
||||
placeholder="••••••••"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full py-3 px-6 bg-indigo-600 hover:bg-indigo-500 text-white font-semibold
|
||||
rounded-lg transition duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-400"
|
||||
>
|
||||
Sign in
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endslot
|
||||
@end
|
||||
8
resources/views/pages/errors/not_found.edge
Normal file
8
resources/views/pages/errors/not_found.edge
Normal file
@@ -0,0 +1,8 @@
|
||||
<h1>
|
||||
404 - Page not found
|
||||
</h1>
|
||||
<p>
|
||||
This template is rendered by the
|
||||
<a href="http://docs.adonisjs.com/guides/exception-handling#status-pages">status pages feature</a>
|
||||
of the global exception handler.
|
||||
</p>
|
||||
8
resources/views/pages/errors/server_error.edge
Normal file
8
resources/views/pages/errors/server_error.edge
Normal file
@@ -0,0 +1,8 @@
|
||||
<h1>
|
||||
{{ error.code }} - Server error
|
||||
</h1>
|
||||
<p>
|
||||
This template is rendered by the
|
||||
<a href="http://docs.adonisjs.com/guides/exception-handling#status-pages">status pages feature</a>
|
||||
of the global exception handler.
|
||||
</p>
|
||||
408
resources/views/pages/home.edge
Normal file
408
resources/views/pages/home.edge
Normal file
@@ -0,0 +1,408 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>
|
||||
AdonisJS - A fully featured web framework for Node.js
|
||||
</title>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.bunny.net" />
|
||||
<link
|
||||
href="https://fonts.bunny.net/css?family=instrument-sans:400,400i,500,500i,600,600i,700,700i"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--sand-1: #fdfdfc;
|
||||
--sand-2: #f9f9f8;
|
||||
--sand-3: #f1f0ef;
|
||||
--sand-4: #e9e8e6;
|
||||
--sand-5: #e2e1de;
|
||||
--sand-6: #dad9d6;
|
||||
--sand-7: #cfceca;
|
||||
--sand-8: #bcbbb5;
|
||||
--sand-9: #8d8d86;
|
||||
--sand-10: #82827c;
|
||||
--sand-11: #63635e;
|
||||
--sand-12: #21201c;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: [ "Instrument Sans", "sans-serif" ]
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
DEFAULT: "#5A45FF",
|
||||
lighter: "#a599ff"
|
||||
},
|
||||
sand: {
|
||||
1: "var(--sand-1)",
|
||||
2: "var(--sand-2)",
|
||||
3: "var(--sand-3)",
|
||||
4: "var(--sand-4)",
|
||||
5: "var(--sand-5)",
|
||||
6: "var(--sand-6)",
|
||||
7: "var(--sand-7)",
|
||||
8: "var(--sand-8)",
|
||||
9: "var(--sand-9)",
|
||||
10: "var(--sand-10)",
|
||||
11: "var(--sand-11)",
|
||||
12: "var(--sand-12)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@stack('dumper')
|
||||
</head>
|
||||
<body class="min-h-screen w-screen font-sans">
|
||||
<div
|
||||
class="fixed xl:absolute left-8 right-8 top-0 bottom-0 xl:inset-0 max-w-screen-xl mx-auto before:content-[''] before:[background:repeating-linear-gradient(0deg,var(--sand-5)_0_4px,transparent_0_8px)] before:absolute before:top-0 before:left-0 before:h-full before:w-px after:content-[''] after:[background:repeating-linear-gradient(0deg,var(--sand-5)_0_4px,transparent_0_8px)] after:absolute after:top-0 after:right-0 after:h-full after:w-px"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="pt-4 h-full flex flex-col">
|
||||
{{-- Header --}}
|
||||
<div class="grow pb-4 bg-gradient-to-b from-sand-1 to-sand-2 flex justify-center items-center">
|
||||
<a href="https://adonisjs.com" target="_blank" class="isolate">
|
||||
<svg class="w-16 h-16 fill-primary" viewBox="0 0 33 33">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M0 16.333c0 13.173 3.16 16.333 16.333 16.333 13.173 0 16.333-3.16 16.333-16.333C32.666 3.16 29.506 0 16.333 0 3.16 0 0 3.16 0 16.333Zm6.586 3.393L11.71 8.083c.865-1.962 2.528-3.027 4.624-3.027 2.096 0 3.759 1.065 4.624 3.027l5.123 11.643c.233.566.432 1.297.432 1.93 0 2.893-2.029 4.923-4.923 4.923-.986 0-1.769-.252-2.561-.506-.812-.261-1.634-.526-2.695-.526-1.048 0-1.89.267-2.718.529-.801.253-1.59.503-2.538.503-2.894 0-4.923-2.03-4.923-4.924 0-.632.2-1.363.432-1.929Zm9.747-9.613-5.056 11.443c1.497-.699 3.227-1.032 5.056-1.032 1.763 0 3.56.333 4.99 1.032l-4.99-11.444Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Bento with documentation, Adocasts, packages and Discord --}}
|
||||
<div
|
||||
class="isolate mt-10 max-w-screen-xl mx-auto px-16 xl:px-8 grid grid-cols-1 xl:grid-cols-2 xl:grid-rows-3 gap-8"
|
||||
>
|
||||
<article
|
||||
class="row-span-3 relative p-6 shadow-sm hover:shadow border border-sand-7 hover:border-sand-8 rounded-2xl transition ease-in-out duration-700 group flex flex-col gap-8"
|
||||
>
|
||||
<div class="relative opacity-80">
|
||||
<svg fill="none" viewBox="0 0 240 105">
|
||||
<path fill="#F9F9F8" d="M0 4a4 4 0 0 1 4-4h232a4 4 0 0 1 4 4v101H0V4Z" />
|
||||
<g fill="#000" fill-rule="evenodd" clip-path="url(#a)" clip-rule="evenodd">
|
||||
<path
|
||||
d="M24 11.444c0 4.391 1.053 5.445 5.444 5.445s5.445-1.054 5.445-5.445c0-4.39-1.054-5.444-5.445-5.444C25.054 6 24 7.053 24 11.444Zm2.195 1.131 1.708-3.88c.288-.655.843-1.01 1.541-1.01.699 0 1.253.355 1.542 1.01l1.707 3.88c.078.189.144.433.144.644 0 .964-.676 1.64-1.64 1.64-.33 0-.59-.083-.854-.168-.271-.087-.545-.175-.899-.175-.35 0-.63.089-.906.176-.267.085-.53.168-.846.168-.964 0-1.64-.677-1.64-1.641 0-.211.066-.455.143-.644Zm3.25-3.204-1.686 3.814c.499-.233 1.075-.344 1.685-.344.588 0 1.187.111 1.664.344l-1.664-3.814Zm26.473-.678c-.378 0-.65.268-.65.64 0 .374.272.641.65.641s.651-.267.651-.64-.273-.64-.65-.64Zm-11.907 5.502c-1.009 0-1.738-.745-1.738-1.91 0-1.187.73-1.933 1.737-1.933.468 0 .814.158 1.019.468V8.86h1.05v5.25h-1.05v-.372c-.2.304-.546.456-1.019.456Zm-.667-1.91c0-.652.352-1.077.887-1.077.54 0 .887.42.887 1.071 0 .64-.346 1.056-.887 1.056-.535 0-.887-.415-.887-1.05Zm4.384-.011c0-.646.351-1.06.877-1.06.53 0 .882.414.882 1.06 0 .646-.352 1.06-.883 1.06-.525 0-.876-.414-.876-1.06Zm11.571.835c0 .194-.147.31-.52.31-.42 0-.682-.221-.682-.489h-1.05c.026.725.714 1.265 1.711 1.265.946 0 1.55-.42 1.55-1.165 0-.557-.358-.945-1.066-1.087l-.762-.152c-.23-.047-.367-.163-.367-.315 0-.226.23-.347.525-.347.42 0 .583.195.583.426h.997c-.026-.683-.562-1.203-1.56-1.203-.929 0-1.559.468-1.559 1.176 0 .64.415.93 1.035 1.06l.756.164c.247.052.41.157.41.357Zm-2.85 1.002h-1.05v-3.675h1.05v3.675Zm-4.264-3.675v.384c.268-.31.625-.468 1.066-.468.824 0 1.36.536 1.36 1.365v2.394h-1.05v-2.173c0-.446-.252-.714-.688-.714-.436 0-.688.268-.688.714v2.173h-1.05v-3.675h1.05Zm-3.58-.084c-1.119 0-1.948.809-1.948 1.922s.83 1.921 1.948 1.921c1.123 0 1.953-.808 1.953-1.921s-.83-1.922-1.953-1.922Zm-8.758.856c-.535 0-.887.425-.887 1.076 0 .636.352 1.05.887 1.05.54 0 .887-.414.887-1.055 0-.65-.346-1.07-.887-1.07Zm-1.958 1.076c0 1.166.73 1.911 1.732 1.911.478 0 .82-.152 1.024-.456v.372h1.05v-3.675h-1.05v.384c-.21-.31-.556-.468-1.024-.468-1.003 0-1.732.746-1.732 1.932Z"
|
||||
/>
|
||||
</g>
|
||||
<rect width="8" height="3" x="162" y="9.944" fill="#DAD9D6" rx="1" />
|
||||
<rect width="14" height="3" x="174" y="9.944" fill="#DAD9D6" rx="1" />
|
||||
<rect width="10" height="3" x="192" y="9.944" fill="#DAD9D6" rx="1" />
|
||||
<rect width="10" height="3" x="206" y="9.944" fill="#DAD9D6" rx="1" />
|
||||
<rect width="81" height="6" x="24" y="32" fill="#DAD9D6" rx="2" />
|
||||
<rect width="95" height="6" x="24" y="44" fill="#DAD9D6" rx="2" />
|
||||
<rect width="16" height="5" x="24" y="60" fill="#21201C" rx="1" />
|
||||
<path fill="#DAD9D6" d="M24 85a4 4 0 0 1 4-4h184a4 4 0 0 1 4 4v20H24V85Z" />
|
||||
<path fill="url(#b)" fill-opacity=".2" d="M24 85a4 4 0 0 1 4-4h184a4 4 0 0 1 4 4v20H24V85Z" />
|
||||
<defs>
|
||||
<linearGradient id="b" x1="120" x2="120" y1="81" y2="105" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-opacity="0" />
|
||||
<stop offset="1" stop-color="#82827C" />
|
||||
</linearGradient>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M24 6h36.307v10.889H24z" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<div class="absolute left-0 right-0 bottom-0 h-16 bg-gradient-to-b from-white/0 to-white">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-4">
|
||||
<div class="shrink-0 w-10 h-10 bg-primary/20 rounded-md flex justify-center items-center">
|
||||
<svg class="h-6 w-6 fill-primary" viewBox="0 0 256 256">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M208 24H72a32 32 0 0 0-32 32v168a8 8 0 0 0 8 8h144a8 8 0 0 0 0-16H56a16 16 0 0 1 16-16h136a8 8 0 0 0 8-8V32a8 8 0 0 0-8-8m-88 16h48v72l-19.21-14.4a8 8 0 0 0-9.6 0L120 112Zm80 144H72a31.8 31.8 0 0 0-16 4.29V56a16 16 0 0 1 16-16h32v88a8 8 0 0 0 12.8 6.4L144 114l27.21 20.4A8 8 0 0 0 176 136a8 8 0 0 0 8-8V40h16Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-lg font-semibold">
|
||||
<a href="https://docs.adonisjs.com" target="_blank">
|
||||
<span>Documentation</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-700">
|
||||
Dive into the official documentation to learn AdonisJS. Read carefully to discover an unmatched set of features, best practices and developer experience. Through examples, guides and API references, you'll find everything you need to build your next project. From installation to deployment, we've got you covered.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative p-6 shadow-sm hover:shadow border border-sand-7 hover:border-sand-8 rounded-2xl transition ease-in-out duration-700 group flex flex-row gap-4"
|
||||
>
|
||||
<div class="shrink-0 w-10 h-10 bg-primary/20 rounded-md flex justify-center items-center">
|
||||
<svg class="h-6 w-6 fill-primary" viewBox="0 0 256 256">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m164.44 105.34-48-32A8 8 0 0 0 104 80v64a8 8 0 0 0 12.44 6.66l48-32a8 8 0 0 0 0-13.32M120 129.05V95l25.58 17ZM216 40H40a16 16 0 0 0-16 16v112a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16m0 128H40V56h176zm16 40a8 8 0 0 1-8 8H32a8 8 0 0 1 0-16h192a8 8 0 0 1 8 8"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-lg font-semibold">
|
||||
<a href="https://adocasts.com" target="_blank">
|
||||
<span>Adocasts</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-700">
|
||||
Level up your development and Adonis skills with hours of video content, from beginner to advanced, through databases, testing, and more.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative p-6 shadow-sm hover:shadow border border-sand-7 hover:border-sand-8 rounded-2xl transition ease-in-out duration-700 group flex flex-row gap-4"
|
||||
>
|
||||
<div class="shrink-0 w-10 h-10 bg-primary/20 rounded-md flex justify-center items-center">
|
||||
<svg class="h-6 w-6 fill-primary" viewBox="0 0 256 256">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M208 96a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16h-32a16 16 0 0 0-16 16v8H96v-8a16 16 0 0 0-16-16H48a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h8v64h-8a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16v-8h64v8a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-8V96Zm-32-48h32v32h-32ZM48 48h32v15.9a.5.5 0 0 0 0 .2V80H48Zm32 160H48v-32h32v15.9a.5.5 0 0 0 0 .2zm128 0h-32v-32h32Zm-24-48h-8a16 16 0 0 0-16 16v8H96v-8a16 16 0 0 0-16-16h-8V96h8a16 16 0 0 0 16-16v-8h64v8a16 16 0 0 0 16 16h8Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-lg font-semibold">
|
||||
<a href="https://packages.adonisjs.com" target="_blank">
|
||||
<span>Packages</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-700">
|
||||
Supercharge your AdonisJS application with packages built and maintained by both the core team and the community.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative p-6 shadow-sm hover:shadow border border-sand-7 hover:border-sand-8 rounded-2xl transition ease-in-out duration-700 group flex flex-row gap-4"
|
||||
>
|
||||
<div class="shrink-0 w-10 h-10 bg-primary/20 rounded-md flex justify-center items-center">
|
||||
<svg class="h-6 w-6 fill-primary" viewBox="0 0 256 256">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m0 192a88 88 0 1 1 88-88 88.1 88.1 0 0 1-88 88m44.42-143.16-64 32a8.05 8.05 0 0 0-3.58 3.58l-32 64A8 8 0 0 0 80 184a8.1 8.1 0 0 0 3.58-.84l64-32a8.05 8.05 0 0 0 3.58-3.58l32-64a8 8 0 0 0-10.74-10.74M138 138l-40.11 20.11L118 118l40.15-20.07Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<h2 class="text-lg font-semibold">
|
||||
<a href="https://discord.gg/vDcEjq6" target="_blank">
|
||||
<span>Discord</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-700">
|
||||
Never get lost again, ask questions, and share your knowledge or projects with a growing and supportive community. Join us.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
{{-- Features --}}
|
||||
<div class="grow mt-10 mb-8 px-16 xl:px-8 max-w-screen-xl mx-auto">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4">
|
||||
<article
|
||||
class="relative py-4 px-5 bg-white border border-transparent rounded-lg hover:border-sand-8 hover:shadow-sm transition duration-100 ease-in-out group"
|
||||
>
|
||||
<h2 class="font-semibold text-sand-12">
|
||||
<a href="https://lucid.adonisjs.com" target="_blank" class="flex flex-row gap-2">
|
||||
<span class="bg-[#D5EAE7] h-6 w-6 flex justify-center items-center rounded">
|
||||
<svg class="h-4 w-4 fill-[#0E766E]" viewBox="0 0 24 24">
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6" />
|
||||
<path d="M4 6v6a8 3 0 0 0 16 0V6" />
|
||||
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Lucid</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="mt-4 text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-100">
|
||||
A SQL ORM with a powerful query builder, active record, migrations, and model factories. Everything you need to work with databases.
|
||||
</p>
|
||||
|
||||
<svg
|
||||
class="absolute top-4 right-5 opacity-0 group-hover:opacity-100 text-sand-9 w-4 h-4 transition ease-in-out duration-100"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6m-7 1 9-9m-5 0h5v5"
|
||||
/>
|
||||
</svg>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative py-4 px-5 bg-white border border-transparent rounded-lg hover:border-sand-8 hover:shadow-sm transition duration-100 ease-in-out group"
|
||||
>
|
||||
<h2 class="font-semibold text-sand-12">
|
||||
<a href="https://vinejs.dev/" target="_blank" class="flex flex-row gap-2">
|
||||
<span class="bg-[#F3DBFC] h-6 w-6 flex justify-center items-center rounded">
|
||||
<svg class="h-4 w-4 fill-[#CA5AF2]" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 3a12 12 0 0 0 8.5 3A12 12 0 0 1 12 21 12 12 0 0 1 3.5 6 12 12 0 0 0 12 3"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Vine</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="mt-4 text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-100">
|
||||
A simple yet feature rich and type-safe form data validation. It comes with 50+ built-in rules and an expressive API to define custom rules.
|
||||
</p>
|
||||
|
||||
<svg
|
||||
class="absolute top-4 right-5 opacity-0 group-hover:opacity-100 text-sand-9 w-4 h-4 transition ease-in-out duration-100"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6m-7 1 9-9m-5 0h5v5"
|
||||
/>
|
||||
</svg>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative py-4 px-5 bg-white border border-transparent rounded-lg hover:border-sand-8 hover:shadow-sm transition duration-100 ease-in-out group"
|
||||
>
|
||||
<h2 class="font-semibold text-sand-12">
|
||||
<a href="https://edgejs.dev/" target="_blank" class="flex flex-row gap-2">
|
||||
<span class="bg-[#B8EAE0] h-6 w-6 flex justify-center items-center rounded">
|
||||
<svg class="h-4 w-4 fill-[#4BBBA5]" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 4a2 2 0 0 0-2 2v3a2 3 0 0 1-2 3 2 3 0 0 1 2 3v3a2 2 0 0 0 2 2M17 4a2 2 0 0 1 2 2v3a2 3 0 0 0 2 3 2 3 0 0 0-2 3v3a2 2 0 0 1-2 2"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Edge</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="mt-4 text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-100">
|
||||
Write your views with ease and enjoy the power of a simple, modern and battteries included template engine. You'll love it.
|
||||
</p>
|
||||
|
||||
<svg
|
||||
class="absolute top-4 right-5 opacity-0 group-hover:opacity-100 text-sand-9 w-4 h-4 transition ease-in-out duration-100"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6m-7 1 9-9m-5 0h5v5"
|
||||
/>
|
||||
</svg>
|
||||
</article>
|
||||
|
||||
<article
|
||||
class="relative py-4 px-5 bg-white border border-transparent rounded-lg hover:border-sand-8 hover:shadow-sm transition duration-100 ease-in-out group"
|
||||
>
|
||||
<h2 class="font-semibold text-sand-12">
|
||||
<a href="https://japa.dev" target="_blank" class="flex flex-row gap-2">
|
||||
<span class="bg-[#FACDDC] h-6 w-6 flex justify-center items-center rounded">
|
||||
<svg class="h-4 w-4 fill-[#DD3074]" viewBox="0 0 256 256">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m240.49 83.51-60-60a12 12 0 0 0-17 0L34.28 152.75a48.77 48.77 0 0 0 69 69l111.2-111.26 21.31-7.11a12 12 0 0 0 4.7-19.87M86.28 204.75a24.77 24.77 0 0 1-35-35l28.13-28.13c7.73-2.41 19.58-3 35.06 5a84 84 0 0 0 21.95 8ZM204.2 88.62a12.15 12.15 0 0 0-4.69 2.89l-38.89 38.9c-7.73 2.41-19.58 3-35.06-5a84 84 0 0 0-21.94-8L172 49l37.79 37.79Z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span>Japa</span>
|
||||
<span class="absolute inset-0"></span>
|
||||
</a>
|
||||
</h2>
|
||||
|
||||
<p class="mt-4 text-sm text-sand-11 group-hover:text-sand-12 transition ease-in-out duration-100">
|
||||
From JSON API tests using Open API schema to browser tests with Playwright, it comes with everything you need to test your application.
|
||||
</p>
|
||||
|
||||
<svg
|
||||
class="absolute top-4 right-5 opacity-0 group-hover:opacity-100 text-sand-9 w-4 h-4 transition ease-in-out duration-100"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 6H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6m-7 1 9-9m-5 0h5v5"
|
||||
/>
|
||||
</svg>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="text-sm text-center [&>code]:font-medium [&>code]:text-[#a599ff] bg-sand-12 text-sand-1 relative py-2"
|
||||
>
|
||||
Route for this page is registered in <code>start/routes.ts</code> file, rendering <code>resources/views/pages/home.edge</code> template
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
12
start/env.js
Normal file
12
start/env.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Env } from '@adonisjs/core/env';
|
||||
export default await Env.create(new URL('../', import.meta.url), {
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test']),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
LOG_LEVEL: Env.schema.string(),
|
||||
SESSION_DRIVER: Env.schema.enum(['cookie', 'memory']),
|
||||
AUTH_USERNAME: Env.schema.string(),
|
||||
AUTH_PASSWORD: Env.schema.string(),
|
||||
});
|
||||
//# sourceMappingURL=env.js.map
|
||||
1
start/env.js.map
Normal file
1
start/env.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../start/env.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAExC,eAAe,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;IAC/D,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;IACzE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;IACzB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;IAC5B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC3C,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;IAO9B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAC;IAO9D,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;IAClC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE;CACnC,CAAC,CAAA"}
|
||||
17
start/kernel.js
Normal file
17
start/kernel.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import router from '@adonisjs/core/services/router';
|
||||
import server from '@adonisjs/core/services/server';
|
||||
server.errorHandler(() => import('#exceptions/handler'));
|
||||
server.use([
|
||||
() => import('#middleware/container_bindings_middleware'),
|
||||
() => import('@adonisjs/static/static_middleware'),
|
||||
() => import('@adonisjs/vite/vite_middleware'),
|
||||
]);
|
||||
router.use([
|
||||
() => import('@adonisjs/core/bodyparser_middleware'),
|
||||
() => import('@adonisjs/session/session_middleware'),
|
||||
() => import('@adonisjs/shield/shield_middleware'),
|
||||
]);
|
||||
export const middleware = router.named({
|
||||
auth: () => import('#middleware/auth_middleware'),
|
||||
});
|
||||
//# sourceMappingURL=kernel.js.map
|
||||
1
start/kernel.js.map
Normal file
1
start/kernel.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"kernel.js","sourceRoot":"","sources":["../../start/kernel.ts"],"names":[],"mappings":"AAUA,OAAO,MAAM,MAAM,gCAAgC,CAAA;AACnD,OAAO,MAAM,MAAM,gCAAgC,CAAA;AAMnD,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAA;AAOxD,MAAM,CAAC,GAAG,CAAC;IACT,GAAG,EAAE,CAAC,MAAM,CAAC,2CAA2C,CAAC;IACzD,GAAG,EAAE,CAAC,MAAM,CAAC,oCAAoC,CAAC;IAClD,GAAG,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC;CAC/C,CAAC,CAAA;AAMF,MAAM,CAAC,GAAG,CAAC;IACT,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC;IACpD,GAAG,EAAE,CAAC,MAAM,CAAC,sCAAsC,CAAC;IACpD,GAAG,EAAE,CAAC,MAAM,CAAC,oCAAoC,CAAC;CACnD,CAAC,CAAA;AAMF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;IACrC,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,6BAA6B,CAAC;CAClD,CAAC,CAAA"}
|
||||
19
start/routes.js
Normal file
19
start/routes.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { middleware } from '#start/kernel';
|
||||
mkdirSync(app.publicPath('uploads'), { recursive: true });
|
||||
const AuthController = () => import('#controllers/auth_controller');
|
||||
const UploadController = () => import('#controllers/upload_controller');
|
||||
const MediaController = () => import('#controllers/media_controller');
|
||||
router.get('/login', [AuthController, 'showLogin']);
|
||||
router.post('/login', [AuthController, 'login']);
|
||||
router.get('/api/media/:filename', [MediaController, 'serve']);
|
||||
router
|
||||
.group(() => {
|
||||
router.get('/', [MediaController, 'index']);
|
||||
router.post('/upload', [UploadController, 'store']);
|
||||
router.get('/logout', [AuthController, 'logout']);
|
||||
})
|
||||
.use(middleware.auth());
|
||||
//# sourceMappingURL=routes.js.map
|
||||
1
start/routes.js.map
Normal file
1
start/routes.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../start/routes.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,MAAM,MAAM,gCAAgC,CAAA;AACnD,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAG1C,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;AAGzD,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAA;AACnE,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAA;AACvE,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC,CAAA;AAIrE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAA;AACnD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAA;AAGhD,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAA;AAI9D,MAAM;KACH,KAAK,CAAC,GAAG,EAAE;IACV,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAA;IACnD,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAA;AACnD,CAAC,CAAC;KACD,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAA"}
|
||||
15
tests/bootstrap.js
vendored
Normal file
15
tests/bootstrap.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { assert } from '@japa/assert';
|
||||
import app from '@adonisjs/core/services/app';
|
||||
import { pluginAdonisJS } from '@japa/plugin-adonisjs';
|
||||
import testUtils from '@adonisjs/core/services/test_utils';
|
||||
export const plugins = [assert(), pluginAdonisJS(app)];
|
||||
export const runnerHooks = {
|
||||
setup: [],
|
||||
teardown: [],
|
||||
};
|
||||
export const configureSuite = (suite) => {
|
||||
if (['browser', 'functional', 'e2e'].includes(suite.name)) {
|
||||
return suite.setup(() => testUtils.httpServer().start());
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=bootstrap.js.map
|
||||
1
tests/bootstrap.js.map
Normal file
1
tests/bootstrap.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../tests/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,GAAG,MAAM,6BAA6B,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,SAAS,MAAM,oCAAoC,CAAA;AAU1D,MAAM,CAAC,MAAM,OAAO,GAAsB,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;AASzE,MAAM,CAAC,MAAM,WAAW,GAAiD;IACvE,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;CACb,CAAA;AAMD,MAAM,CAAC,MAAM,cAAc,GAA6B,CAAC,KAAK,EAAE,EAAE;IAChE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,CAAA;IAC1D,CAAC;AACH,CAAC,CAAA"}
|
||||
11
vite.config.js
Normal file
11
vite.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import adonisjs from '@adonisjs/vite/client';
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
adonisjs({
|
||||
entrypoints: ['resources/css/app.css', 'resources/js/app.js'],
|
||||
reload: ['resources/views/**/*.edge'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
//# sourceMappingURL=vite.config.js.map
|
||||
1
vite.config.js.map
Normal file
1
vite.config.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"vite.config.js","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,QAAQ,MAAM,uBAAuB,CAAA;AAE5C,eAAe,YAAY,CAAC;IAC1B,OAAO,EAAE;QACP,QAAQ,CAAC;YAKP,WAAW,EAAE,CAAC,uBAAuB,EAAE,qBAAqB,CAAC;YAK7D,MAAM,EAAE,CAAC,2BAA2B,CAAC;SACtC,CAAC;KACH;CACF,CAAC,CAAA"}
|
||||
Reference in New Issue
Block a user