- npm added @japa/api-client, @japa/assert, @types/supertest

- webpack added opions['__VUE_PROD_HYDRATION_MISMATCH_DETAILS__'] = false;
- bodyparser config replaced whitelistedMethods with allowedMethods
- extended stardust_provider
- adapted tests for adonisjs v6
This commit is contained in:
Kaimbacher 2024-04-25 15:17:22 +02:00
parent 296c8fd46e
commit bee76f8d5b
23 changed files with 2014 additions and 165 deletions

View File

@ -90,13 +90,22 @@ export default defineConfig({
| and add additional suites. | and add additional suites.
| |
*/ */
tests: { tests: {
suites: [ suites: [
{ {
name: 'functional', files: ['tests/unit/**/*.spec(.ts|.js)'],
files: ['tests/functional/**/*.spec(.ts|.js)'], name: 'unit',
timeout: 60000, timeout: 2000,
}, },
], {
}, files: ['tests/functional/**/*.spec(.ts|.js)'],
name: 'functional',
timeout: 30000,
},
],
forceExit: false,
},
}) })

View File

@ -88,13 +88,17 @@ export default class UserController {
} }
public async disableTwoFactorAuthentication({ auth, response, session }: HttpContext): Promise<void> { public async disableTwoFactorAuthentication({ auth, response, session }: HttpContext): Promise<void> {
const user = auth.user; const user: User | undefined = auth.user;
user.twoFactorSecret = null; if (user) {
user.twoFactorRecoveryCodes = null; user.twoFactorSecret = null;
await user.save(); user.twoFactorRecoveryCodes = null;
await user.save();
session.flash('message', 'Two-factor authentication disabled.');
} else {
session.flash('error', 'User not found.');
}
session.flash('message', 'Two factor authentication disabled.');
return response.redirect().back(); return response.redirect().back();
// return inertia.render('Auth/AccountInfo', { // return inertia.render('Auth/AccountInfo', {
// // status: { // // status: {

View File

@ -38,7 +38,6 @@ import drive from '#services/drive';
import { Exception } from '@adonisjs/core/exceptions'; import { Exception } from '@adonisjs/core/exceptions';
import { MultipartFile } from '@adonisjs/core/types/bodyparser'; import { MultipartFile } from '@adonisjs/core/types/bodyparser';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import app from '@adonisjs/core/services/app';
interface Dictionary { interface Dictionary {
[index: string]: string; [index: string]: string;
} }
@ -446,7 +445,7 @@ export default class DatasetController {
const mimeType = file.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type const mimeType = file.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type
const datasetFolder = `files/${dataset.id}`; const datasetFolder = `files/${dataset.id}`;
// const size = file.size; // const size = file.size;
await file.move(app.makePath(datasetFolder), { await file.move(drive.makePath(datasetFolder), {
name: fileName, name: fileName,
overwrite: true, // overwrite in case of conflict overwrite: true, // overwrite in case of conflict
}); });
@ -918,10 +917,13 @@ export default class DatasetController {
} }
// move to disk: // move to disk:
const fileName = `file-${cuid()}.${fileData.extname}`; const fileName = `file-${cuid()}.${fileData.extname}`; //'file-ls0jyb8xbzqtrclufu2z2e0c.pdf'
const datasetFolder = `files/${dataset.id}`; const datasetFolder = `files/${dataset.id}`; // 'files/307'
await fileData.moveToDisk(datasetFolder, { name: fileName, overwrite: true }, 'local'); // await fileData.moveToDisk(datasetFolder, { name: fileName, overwrite: true }, 'local');
// let path = coverImage.filePath; await fileData.move(drive.makePath(datasetFolder), {
name: fileName,
overwrite: true, // overwrite in case of conflict
});
//save to db: //save to db:
const { clientFileName, sortOrder } = this.extractVariableNameAndSortOrder(fileData.clientName); const { clientFileName, sortOrder } = this.extractVariableNameAndSortOrder(fileData.clientName);

View File

@ -29,7 +29,7 @@ export default class HttpExceptionHandler extends ExceptionHandler {
* codes. You might want to enable them in production only, but feel * codes. You might want to enable them in production only, but feel
* free to enable them in development as well. * free to enable them in development as well.
*/ */
protected renderStatusPages = true; //app.inProduction; protected renderStatusPages = app.inProduction;
/** /**
* Status pages is a collection of error code range and a callback * Status pages is a collection of error code range and a callback

View File

@ -1,27 +1,47 @@
import type { HttpContext } from '@adonisjs/core/http'; import type { HttpContext } from '@adonisjs/core/http';
import type { NextFn } from '@adonisjs/core/types/http'; import type { NextFn } from '@adonisjs/core/types/http';
declare global {
function myFunction(): boolean;
var myVariable: number;
interface StardustData {
pathname?: string;
namedRoutes?: Record<string, string>;
}
var stardust: StardustData;
}
declare global {}
export default class StardustMiddleware { export default class StardustMiddleware {
async handle(ctx: HttpContext, next: NextFn): Promise<void> { async handle(ctx: HttpContext, next: NextFn): Promise<void> {
/** /**
* Middleware logic goes here (before the next call) * Middleware logic goes here (before the next call)
*/ */
// console.log(ctx);
const { pathname } = new URL(ctx.request.completeUrl());
globalThis.stardust = {
...globalThis.stardust,
pathname,
};
/** // Check if the request is an API request
* Call next method in the pipeline and return its output if (!ctx.request.url().startsWith('/api')) {
*/ // Middleware logic for non-API requests
const output = await next(); const { pathname } = new URL(ctx.request.completeUrl()); // '/', '/app/login'
return output; globalThis.myFunction = () => {
return true;
};
globalThis.myVariable = 1;
globalThis.stardust = {
...globalThis.stardust,
pathname,
};
/**
* Call next method in the pipeline and return its output
*/
await next();
} else {
// Skip middleware for API requests
await next();
}
} }
} }
// import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
// export default class StardustMiddleware {
// handle({ request }: HttpContextContract, next: () => Promise<void>): Promise<void>;
// }

View File

@ -19,7 +19,7 @@ const bodyParserConfig = defineConfig({
| to avoid body parsing for `GET` requests. | to avoid body parsing for `GET` requests.
| |
*/ */
whitelistedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'], allowedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -6,8 +6,7 @@
*/ */
import env from '#start/env'; import env from '#start/env';
import { defineConfig } from "@adonisjs/core/hash"; import { defineConfig, drivers } from '@adonisjs/core/hash';
import { drivers } from "@adonisjs/core/hash";
import { laravelDriver } from '../providers/HashDriver/index.js'; import { laravelDriver } from '../providers/HashDriver/index.js';
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -18,8 +17,8 @@ import { laravelDriver } from '../providers/HashDriver/index.js';
| defined inside `contracts` directory. | defined inside `contracts` directory.
| |
*/ */
export default defineConfig({ const hashConfig = defineConfig({
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default hasher | Default hasher
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -28,10 +27,10 @@ export default defineConfig({
| free to change the default value | free to change the default value
| |
*/ */
default: env.get('HASH_DRIVER', 'scrypt'), default: env.get('HASH_DRIVER', 'scrypt'),
list: { list: {
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| scrypt | scrypt
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -44,16 +43,16 @@ export default defineConfig({
| https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback | https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback
| |
*/ */
scrypt: drivers.scrypt({ scrypt: drivers.scrypt({
cost: 16384, cost: 16384,
blockSize: 8, blockSize: 8,
parallelization: 1, parallelization: 1,
saltSize: 16, saltSize: 16,
keyLength: 64, keyLength: 64,
maxMemory: 32 * 1024 * 1024, maxMemory: 32 * 1024 * 1024,
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Argon | Argon
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -66,15 +65,15 @@ export default defineConfig({
| npm install phc-argon2 | npm install phc-argon2
| |
*/ */
argon: drivers.argon2({ argon: drivers.argon2({
variant: 'id', variant: 'id',
iterations: 3, iterations: 3,
memory: 4096, memory: 4096,
parallelism: 1, parallelism: 1,
saltSize: 16, saltSize: 16,
}), }),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Bcrypt | Bcrypt
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -87,18 +86,18 @@ export default defineConfig({
| npm install phc-bcrypt | npm install phc-bcrypt
| |
*/ */
bcrypt: drivers.bcrypt({ bcrypt: drivers.bcrypt({
rounds: 10, rounds: 10,
}), }),
laravel: laravelDriver({ laravel: laravelDriver({
rounds: 10, rounds: 10,
}), }),
},
},
}); });
export default hashConfig;
declare module '@adonisjs/core/types' { declare module '@adonisjs/core/types' {
export interface HashersList extends InferHashers<typeof hashConfig> { } export interface HashersList extends InferHashers<typeof hashConfig> {}
} }

View File

@ -9,7 +9,7 @@ import env from '#start/env';
import app from '@adonisjs/core/services/app'; import app from '@adonisjs/core/services/app';
import { defineConfig, stores } from '@adonisjs/session'; import { defineConfig, stores } from '@adonisjs/session';
export default defineConfig({ const sessionConfig = defineConfig({
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Enable/Disable sessions | Enable/Disable sessions
@ -119,8 +119,9 @@ export default defineConfig({
| must be defined inside `config/redis.ts` file as well. | must be defined inside `config/redis.ts` file as well.
| |
*/ */
redisConnection: 'local', // redisConnection: 'local',
stores: { stores: {
cookie: stores.cookie(), cookie: stores.cookie(),
}, },
}); });
export default sessionConfig;

1733
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,8 @@
"@babel/plugin-transform-runtime": "^7.19.6", "@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2", "@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6", "@babel/preset-typescript": "^7.18.6",
"@japa/api-client": "^2.0.3",
"@japa/assert": "^3.0.0",
"@japa/plugin-adonisjs": "^3.0.0", "@japa/plugin-adonisjs": "^3.0.0",
"@japa/runner": "^3.1.1", "@japa/runner": "^3.1.1",
"@mdi/js": "^7.1.96", "@mdi/js": "^7.1.96",
@ -46,6 +48,7 @@
"@types/qrcode": "^1.5.5", "@types/qrcode": "^1.5.5",
"@types/source-map-support": "^0.5.6", "@types/source-map-support": "^0.5.6",
"@types/sprintf-js": "^1.1.4", "@types/sprintf-js": "^1.1.4",
"@types/supertest": "^6.0.2",
"@vue/tsconfig": "^0.4.0", "@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"babel-preset-typescript-vue3": "^2.0.17", "babel-preset-typescript-vue3": "^2.0.17",

View File

@ -1,21 +1,24 @@
import fsExtra from 'fs-extra' import fsExtra from 'fs-extra';
// import { RouterContract } from '@ioc:Adonis/Core/Route'; // import { RouterContract } from '@ioc:Adonis/Core/Route';
// import { Visibility, DriveFileStats, ContentHeaders, LocalDriverConfig, LocalDriverContract, DirectoryListingContract, LocalDriveListItem } from '@ioc:Adonis/Core/Drive'; // import { Visibility, DriveFileStats, ContentHeaders, LocalDriverConfig, LocalDriverContract, DirectoryListingContract, LocalDriveListItem } from '@ioc:Adonis/Core/Drive';
import { CannotGetMetaDataException, CannotDeleteFileException, CannotListDirectoryException } from '../exceptions/index.js';
import PathPrefixer from '../path_prefixer/index.js';
import { import {
LocalDriverContract, CannotGetMetaDataException,
LocalDriverConfig, CannotDeleteFileException,
DriverContract, CannotListDirectoryException,
DriveListItem, CannotMoveFileException,
} from '../src/types/drive.js'; CannotGenerateUrlException,
} from '../exceptions/index.js';
import PathPrefixer from '../path_prefixer/index.js';
import { LocalDriverContract, LocalDriverConfig, DriverContract, DriveListItem } from '../src/types/drive.js';
import { AsyncIterableArray } from '../src/iterable_array.js'; import { AsyncIterableArray } from '../src/iterable_array.js';
import router from '@adonisjs/core/services/router'
/** /**
* Local driver interacts with the local file system * Local driver interacts with the local file system
*/ */
export class LocalDriver implements LocalDriverContract { export class LocalDriver implements LocalDriverContract {
private diskName: string; private diskName: string;
private routeName: string;
private config; private config;
// private router; // private router;
// private routeName; // private routeName;
@ -40,7 +43,7 @@ export class LocalDriver implements LocalDriverContract {
this.diskName = diskName; this.diskName = diskName;
this.config = config; this.config = config;
// this.router = router; // this.router = router;
// this.routeName = LocalFileServer_1.LocalFileServer.makeRouteName(this.diskName); this.routeName = ""; //LocalFileServer_1.LocalFileServer.makeRouteName(this.diskName);
/** /**
* Reference to the underlying adapter. Which is * Reference to the underlying adapter. Which is
* fs-extra * fs-extra
@ -56,10 +59,16 @@ export class LocalDriver implements LocalDriverContract {
this.prefixer = PathPrefixer.fromPath(this.config.root); //root: '/storage/app/public', this.prefixer = PathPrefixer.fromPath(this.config.root); //root: '/storage/app/public',
} }
/** /**
* A boolean to find if the location path exists or not * Returns a URL for a given location path
*/ */
exists(location: string): Promise<boolean>; public async getUrl(location: string) {
if (!this.config.serveFiles) {
throw CannotGenerateUrlException.invoke(location, this.diskName);
}
return router.makeUrl(this.routeName);
}
/** /**
* A boolean to find if the location path exists or not * A boolean to find if the location path exists or not
*/ */
@ -90,6 +99,21 @@ export class LocalDriver implements LocalDriverContract {
} }
} }
public async move(source: string, destination: string): Promise<void> {
try {
let sourcePath = this.makePath(source); //'/storage/app/public/tmp/rtwgliatumwwpd4vpayo4ymg'
let destinationPath = this.makePath(destination);
await this.adapter.move(sourcePath, destinationPath, {
overwrite: true,
});
await this.adapter.move(this.makePath(source), this.makePath(destination), {
overwrite:true
});
} catch (error) {
throw CannotMoveFileException.invoke(source, destination, error);
}
}
/** /**
* Return a listing directory iterator for given location. * Return a listing directory iterator for given location.
*/ */
@ -98,7 +122,9 @@ export class LocalDriver implements LocalDriverContract {
const fullPath = this.makePath(location); //'/storage/app/public/files/307' const fullPath = this.makePath(location); //'/storage/app/public/files/307'
// let dirListing: DirectoryListing<DriverContract, DriveListItem<any>> = new DirectoryListing(this, () => this.getListing(fullPath, location)); // let dirListing: DirectoryListing<DriverContract, DriveListItem<any>> = new DirectoryListing(this, () => this.getListing(fullPath, location));
let dirListing: AsyncIterableArray<DriverContract, DriveListItem<any>> = new AsyncIterableArray(this, () => this.getListing(fullPath, location)); let dirListing: AsyncIterableArray<DriverContract, DriveListItem<any>> = new AsyncIterableArray(this, () =>
this.getListing(fullPath, location),
);
return dirListing; return dirListing;
// let listing: DriveListItem<fsExtra.Dirent>[] = await this.getListing(fullPath, location); // let listing: DriveListItem<fsExtra.Dirent>[] = await this.getListing(fullPath, location);
// let test = new DirectoryListing(this, listing); // let test = new DirectoryListing(this, listing);

View File

@ -19,7 +19,24 @@ export class CannotDeleteFileException extends Exception {
return error; return error;
} }
} }
/**
* Unable to move file from source to destination
*/
export class CannotMoveFileException extends Exception {
source: string;
destination: string;
original: any;
static invoke(source: string, destination: string, original: any): CannotMoveFileException {
const error = new this(`Cannot move file from "${source}" to "${destination}"`, {
status: 500,
code: 'E_CANNOT_MOVE_FILE',
});
error.source = source;
error.destination = destination;
error.original = original;
return error;
}
}
/** /**
* Custom exception for when file metadata cannot be retrieved * Custom exception for when file metadata cannot be retrieved
*/ */
@ -71,3 +88,22 @@ export class CannotListDirectoryException extends Exception {
return error; return error;
} }
} }
/**
* Unable to generate url for a file. The assets serving is disabled
*/
export class CannotGenerateUrlException extends Exception {
location: string;
static invoke(location: string, diskName: string): CannotGenerateUrlException {
const error = new this(
`Cannot generate URL for location "${location}". Make sure to set "serveFiles = true" for "${diskName}" disk`,
{
status: 500,
code: 'E_CANNOT_GENERATE_URL',
},
);
error.location = location;
return error;
}
}

View File

@ -76,9 +76,11 @@ export default class DriveManager extends Manager<
/** /**
* Make instance of the local driver * Make instance of the local driver
*/ */
protected createLocal(diskName: keyof DriversList, config: LocalDriverConfig) { // protected createLocal(diskName: keyof DriversList, config: LocalDriverConfig) {
protected createLocal(diskName: keyof DriversList, config: LocalDriverConfig) {
// const { LocalDriver } = await import('../drivers/local.js'); // const { LocalDriver } = await import('../drivers/local.js');
return new LocalDriver(diskName, config); return new LocalDriver(diskName, config);
// return new LocalDriver(config);
} }
constructor(application: ApplicationService, config: DriveConfig) { constructor(application: ApplicationService, config: DriveConfig) {
@ -115,7 +117,7 @@ export default class DriveManager extends Manager<
code: 'E_MISSING_DRIVE_CONFIG', code: 'E_MISSING_DRIVE_CONFIG',
}); });
} }
disk = disk || this.getDefaultMappingName(); disk = disk || this.getDefaultMappingName(); //#local'
// if (this.fakeDrive.isFaked(disk)) { // if (this.fakeDrive.isFaked(disk)) {
// return this.fakeDrive.use(disk); // return this.fakeDrive.use(disk);
// } // }
@ -151,4 +153,21 @@ export default class DriveManager extends Manager<
} }
return driver.list(location); return driver.list(location);
} }
/**
* Move a given location path from the source to the desination.
* The missing intermediate directories will be created (if required)
*/
move(source: string, ...args: string[]): Promise<void>{
const driver = this.use();
return driver.move(source, args[0]);
}
/**
* Make absolute path to a given location
*/
public makePath(location: string): string {
const driver = this.use();
return driver.makePath(location);
}
} }

View File

@ -51,7 +51,7 @@ export default class StardustProvider {
edge.global('routes', (cspNonce: string | undefined) => { edge.global('routes', (cspNonce: string | undefined) => {
return ` return `
<script${cspNonce ? ` nonce="${cspNonce}"` : ''}> <script${cspNonce ? ` nonce="${cspNonce}"` : ''}>
(globalThis || window).stardust = { namedRoutes: ${JSON.stringify(namedRoutes)} }; (globalThis || window).stardust = { path: ${JSON.stringify(globalThis.stardust.pathname)}, namedRoutes: ${JSON.stringify(namedRoutes)} };
</script> </script>
`; `;
}); });

View File

@ -52,7 +52,8 @@
"assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js", "assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js",
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js", "assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js",
"assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js", "assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js",
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseButton_vue-resources_js_Components_Ba-dd870d.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseButton_vue-resources_js_Components_Ba-dd870d.js", "assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js",
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js",
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css", "assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css",
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js", "assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js",
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js", "assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js",
@ -61,7 +62,6 @@
"assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js": "http://localhost:8080/assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js", "assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js": "http://localhost:8080/assets/resources_js_Components_Admin_Sort_vue-resources_js_Components_SectionTitleLineWithButton_vue.js",
"assets/resources_js_Components_CardBoxModal_vue.js": "http://localhost:8080/assets/resources_js_Components_CardBoxModal_vue.js", "assets/resources_js_Components_CardBoxModal_vue.js": "http://localhost:8080/assets/resources_js_Components_CardBoxModal_vue.js",
"assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-d5e5fc.js": "http://localhost:8080/assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-d5e5fc.js", "assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-d5e5fc.js": "http://localhost:8080/assets/resources_js_Components_FileUpload_vue-resources_js_Components_FormCheckRadioGroup_vue-resour-d5e5fc.js",
"assets/resources_js_Components_FormInput_vue-resources_js_Layouts_Auth_vue.js": "http://localhost:8080/assets/resources_js_Components_FormInput_vue-resources_js_Layouts_Auth_vue.js",
"assets/fonts/inter-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.40b3b0d5.woff", "assets/fonts/inter-latin-ext-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.40b3b0d5.woff",
"assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.0f9e8d4e.woff2", "assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.0f9e8d4e.woff2",
"assets/fonts/inter-latin-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-400-normal.08a02fd2.woff", "assets/fonts/inter-latin-400-normal.woff": "http://localhost:8080/assets/fonts/inter-latin-400-normal.08a02fd2.woff",
@ -83,10 +83,5 @@
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png", "assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png", "assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png", "assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg", "assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg"
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js",
"assets/resources_js_Pages_Errors_App_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_App_vue.js",
"assets/resources_js_Pages_Errors_ServerError2_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError2_vue.js",
"assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js",
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js"
} }

View File

@ -1,7 +1,7 @@
// import * as util from '../core/utilities'; // import * as util from '../core/utilities';
import { EventEmitter } from './EventEmitter.js'; import { EventEmitter } from './EventEmitter.js';
import type { Map } from 'leaflet/src/map/index.js'; // import type { Map } from 'leaflet/src/map/index.js';
// import type { Map } from 'leaflet'; import type { Map } from 'leaflet';
export abstract class Control<T> extends EventEmitter<T> { export abstract class Control<T> extends EventEmitter<T> {
// @section // @section

View File

@ -4,7 +4,7 @@
<h1 class="text-2xl font-bold text-red-500 mb-4">Error!</h1> <h1 class="text-2xl font-bold text-red-500 mb-4">Error!</h1>
<p class="text-gray-700 mb-4">{{ error }}</p> <p class="text-gray-700 mb-4">{{ error }}</p>
<SectionTitleLineWithButton :icon="mdiLightbulbAlert" :title="code" :main="true"> <SectionTitleLineWithButton :icon="mdiLightbulbAlert" :title="code.toString()" :main="true">
<BaseButton @click.prevent="handleAction" :icon="mdiArrowLeftBoldOutline" label="Dashboard" <BaseButton @click.prevent="handleAction" :icon="mdiArrowLeftBoldOutline" label="Dashboard"
color="white" rounded-full small /> color="white" rounded-full small />
</SectionTitleLineWithButton> </SectionTitleLineWithButton>
@ -42,10 +42,10 @@ export default class AppComponent extends Vue {
error: string; error: string;
@Prop({ @Prop({
type: String, type: Number,
default: () => '', default: () => '',
}) })
code: string; code: number;
// class properties // class properties
mdiLightbulbAlert = mdiLightbulbAlert; mdiLightbulbAlert = mdiLightbulbAlert;

View File

@ -497,7 +497,7 @@ import TableKeywords from '@/Components/TableKeywords.vue';
import FormValidationErrors from '@/Components/FormValidationErrors.vue'; import FormValidationErrors from '@/Components/FormValidationErrors.vue';
import FileUploadComponent from '@/Components/FileUpload.vue'; import FileUploadComponent from '@/Components/FileUpload.vue';
import { MapOptions } from '@/Components/Map/MapOptions'; import { MapOptions } from '@/Components/Map/MapOptions';
import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds'; import { LatLngBoundsExpression } from 'leaflet';
import { LayerOptions } from '@/Components/Map/LayerOptions'; import { LayerOptions } from '@/Components/Map/LayerOptions';
import { import {
mdiImageText, mdiImageText,
@ -659,7 +659,12 @@ const submit = async (): Promise<void> => {
([fileUploads, fileInputs], obj) => { ([fileUploads, fileInputs], obj) => {
if (!obj.id) { if (!obj.id) {
// return MultipartFile for file upload // return MultipartFile for file upload
let file = new File([obj.blob], `${obj.label}?sortOrder=${obj.sort_order}`, { type: obj.type, lastModified: obj.lastModified }); const options: FilePropertyBag = {
type: obj.type,
lastModified: obj.lastModified
};
// let file = new File([obj.blob], `${obj.label}?sortOrder=${obj.sort_order}`, options);
let file = new File([obj.blob], `${obj.label}`, options);
// fileUploads[obj.sort_order] = file; // fileUploads[obj.sort_order] = file;
fileUploads.push(file); fileUploads.push(file);
} else { } else {

View File

@ -22,7 +22,8 @@ import TableKeywords from '@/Components/TableKeywords.vue';
import FormValidationErrors from '@/Components/FormValidationErrors.vue'; import FormValidationErrors from '@/Components/FormValidationErrors.vue';
import FileUploadComponent from '@/Components/FileUpload.vue'; import FileUploadComponent from '@/Components/FileUpload.vue';
import { MapOptions } from '@/Components/Map/MapOptions'; import { MapOptions } from '@/Components/Map/MapOptions';
import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds.js'; // import { LatLngBoundsExpression } from 'leaflet/src/geo/LatLngBounds.js';
import { LatLngBoundsExpression } from 'leaflet';
import { LayerOptions } from '@/Components/Map/LayerOptions'; import { LayerOptions } from '@/Components/Map/LayerOptions';
import { import {

View File

@ -5,9 +5,16 @@
* file. * file.
*/ */
import type { Config } from '@japa/runner'; // import type { Config } from '@japa/runner';
import TestUtils from '@ioc:Adonis/Core/TestUtils'; import type { Config } from '@japa/runner/types';
import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis'; // import TestUtils from '@ioc:Adonis/Core/TestUtils';
import testUtils from '@adonisjs/core/services/test_utils';
// import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis';
import { assert } from '@japa/assert';
import { apiClient } from '@japa/api-client';
import { pluginAdonisJS } from '@japa/plugin-adonisjs';
import app from '@adonisjs/core/services/app';
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -20,7 +27,8 @@ import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-ad
| Feel free to remove existing plugins or add more. | Feel free to remove existing plugins or add more.
| |
*/ */
export const plugins: Required<Config>['plugins'] = [assert(), runFailedTests(), apiClient()]; // export const plugins: Required<Config>['plugins'] = [assert(), runFailedTests(), apiClient()];
export const plugins: Config['plugins'] = [assert(), apiClient(), pluginAdonisJS(app)];
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -32,7 +40,10 @@ export const plugins: Required<Config>['plugins'] = [assert(), runFailedTests(),
| of tests on the terminal. | of tests on the terminal.
| |
*/ */
export const reporters: Required<Config>['reporters'] = [specReporter()]; // export const reporters: Required<Config>['reporters'] = [specReporter()];
export const reporters: Required<Config>['reporters'] = {
activated: ['spec'],
};
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -48,8 +59,9 @@ export const reporters: Required<Config>['reporters'] = [specReporter()];
*/ */
export const runnerHooks: Pick<Required<Config>, 'setup' | 'teardown'> = { export const runnerHooks: Pick<Required<Config>, 'setup' | 'teardown'> = {
setup: [ setup: [
() => TestUtils.ace().loadCommands(), // () => testUtils.ace().loadCommands(),
() => TestUtils.db().migrate() () => testUtils.db().migrate(),
// () => testUtils.httpServer().start(),
], ],
teardown: [], teardown: [],
}; };
@ -67,6 +79,6 @@ export const runnerHooks: Pick<Required<Config>, 'setup' | 'teardown'> = {
*/ */
export const configureSuite: Required<Config>['configureSuite'] = (suite) => { export const configureSuite: Required<Config>['configureSuite'] = (suite) => {
if (suite.name === 'functional') { if (suite.name === 'functional') {
suite.setup(() => TestUtils.httpServer().start()); suite.setup(() => testUtils.httpServer().start());
} }
}; };

View File

@ -2,10 +2,13 @@ import { test } from '@japa/runner';
import supertest from 'supertest'; import supertest from 'supertest';
import db from '@adonisjs/lucid/services/db'; import db from '@adonisjs/lucid/services/db';
import Dataset from '#app/Models/Dataset'; import Dataset from '#app/Models/Dataset';
import server from '@adonisjs/core/services/server'; // Import the server instance // import server from '@adonisjs/core/services/server'; // Import the server instance
// import { Server } from '@adonisjs/core/http';
import User from '#app/Models/User'; import User from '#app/Models/User';
import Role from '#app/Models/Role'; import Role from '#app/Models/Role';
import Permission from '#app/Models/Permission'; import Permission from '#app/Models/Permission';
import { TestContext } from '@japa/runner/core';
const BASE_URL = `http://${process.env.HOST}:${process.env.PORT}`
test.group('DatasetController', (group) => { test.group('DatasetController', (group) => {
// Write your test here // Write your test here
@ -17,9 +20,14 @@ test.group('DatasetController', (group) => {
await db.beginGlobalTransaction(); await db.beginGlobalTransaction();
return () => db.rollbackGlobalTransaction(); return () => db.rollbackGlobalTransaction();
}); });
// group.setup(async () => {
// server = await supertest(BASE_URL);
// });
test('should render dataset release page', async ({ assert }) => {
// var agent = supertest(server.instance);
test('should render dataset release page', async ({ assert }: TestContext) => {
var testAgent = supertest(BASE_URL);
// const user = await loginUser(agent); // const user = await loginUser(agent);
const user = await User.create({ const user = await User.create({
@ -52,7 +60,7 @@ test.group('DatasetController', (group) => {
await user.related('datasets').save(dataset); await user.related('datasets').save(dataset);
// Perform the login request to establish the session // Perform the login request to establish the session
const loginResponse = await supertest(server.instance) const loginResponse = await testAgent
.post('/app/login') .post('/app/login')
// .field('email', user.email) // .field('email', user.email)
// .field('password', user.password) // .field('password', user.password)
@ -62,38 +70,38 @@ test.group('DatasetController', (group) => {
.expect(302); // Assuming the login endpoint redirects, if succesful .expect(302); // Assuming the login endpoint redirects, if succesful
// Extract the session cookies from the login response // Extract the session cookies from the login response
assert.exists(loginResponse.headers['set-cookie']); assert.exists(loginResponse.headers['set-cookie']);
const cookie = loginResponse.headers['set-cookie']; // const cookie = loginResponse.headers['set-cookie'];
// const response = await supertest(server.instance).get(`/submitter/dataset/${dataset.id}/release`).expect(302); //302 if authenticated, else 200 // // const response = await supertest(server.instance).get(`/submitter/dataset/${dataset.id}/release`).expect(302); //302 if authenticated, else 200
const response = await supertest(server.instance) // const response = await testAgent
.get(`/submitter/dataset/${dataset.id}/release`) // .get(`/submitter/dataset/${dataset.id}/release`)
.set('Cookie', cookie) // .set('Cookie', cookie)
.set('X-Requested-With', 'XMLHttpRequest') // Set the X-Requested-With header to mimic an AJAX request // .set('X-Requested-With', 'XMLHttpRequest') // Set the X-Requested-With header to mimic an AJAX request
.set('X-Inertia', 'true') // .set('X-Inertia', 'true')
// .set('X-Inertia-Version', '97c0899ca6e04e77a69f1ad5320e4ebe') // // .set('X-Inertia-Version', '97c0899ca6e04e77a69f1ad5320e4ebe')
.set('Accept', 'text/html, application/xhtml+xml') // .set('Accept', 'text/html, application/xhtml+xml')
.set('Accept-Encoding', 'gzip, deflate, br') // .set('Accept-Encoding', 'gzip, deflate, br')
.set('Connection', 'keep-alive') // .set('Connection', 'keep-alive')
.set( // .set(
'User-Agent', // 'User-Agent',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', // 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
) // )
// .set('Host', 'localhost:4001') // // .set('Host', 'localhost:4001')
// .set('Referer', 'http://localhost:3333/submitter/dataset') // // .set('Referer', 'http://localhost:3333/submitter/dataset')
// .set('Authorization', `Bearer ${authToken}`) // Set the Authorization header with the authentication token . // // .set('Authorization', `Bearer ${authToken}`) // Set the Authorization header with the authentication token .
.expect(200); // .expect(200);
// assert.equal(response.statusCode, 302); // // assert.equal(response.statusCode, 302);
// Add more assertions based on the expected behavior // // Add more assertions based on the expected behavior
// assert.equal(response.header('X-Inertia'), 'true'); // // assert.equal(response.header('X-Inertia'), 'true');
// assert.equal(response.header('Content-Type'), 'application/json'); // // assert.equal(response.header('Content-Type'), 'application/json');
assert.equal(response.headers['x-inertia'], 'true'); // assert.equal(response.headers['x-inertia'], 'true');
assert.equal(response.headers['content-type'], 'application/json; charset=utf-8'); // assert.equal(response.headers['content-type'], 'application/json; charset=utf-8');
const responseData = response.body as { component: string; props: { dataset: any }; url: string }; // const responseData = response.body as { component: string; props: { dataset: any }; url: string };
// assert.equal(responseData.component, 'DatasetReleasePage'); // // assert.equal(responseData.component, 'DatasetReleasePage');
assert.equal(responseData.props.dataset.id, dataset.id); // assert.equal(responseData.props.dataset.id, dataset.id);
}); });
}); });

View File

@ -10,7 +10,8 @@
"node_modules", "node_modules",
"build", "build",
"public", "public",
// "resources/js/**/*", "./resources/js/**/*.vue",
"./resources/js/**/*.ts"
], ],
// "exclude": ["./inertia/**/*"] // "exclude": ["./inertia/**/*"]
"compilerOptions": { "compilerOptions": {
@ -25,10 +26,10 @@
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"paths": { "paths": {
"@/*": ["./resources/js/*.js"], // "@/*": ["./resources/js/*.js"],
"#resources/*": [ // "#resources/*": [
"./resources/js/*.js" // "./resources/js/*.js"
], // ],
"#controllers/*": [ "#controllers/*": [
"./app/controllers/*.js" "./app/controllers/*.js"
], ],

View File

@ -321,6 +321,7 @@ Encore.addLoader(babelLoader)
.configureDefinePlugin((options) => { .configureDefinePlugin((options) => {
options['__VUE_OPTIONS_API__'] = true; options['__VUE_OPTIONS_API__'] = true;
options['__VUE_PROD_DEVTOOLS__'] = false; options['__VUE_PROD_DEVTOOLS__'] = false;
options['__VUE_PROD_HYDRATION_MISMATCH_DETAILS__'] = false;
}); });
// Encore.addAliases({ // Encore.addAliases({