mirror of
https://github.com/ArthurDanjou/artdanj-shortener.git
synced 2026-01-26 17:54:11 +01:00
rework and update deps
This commit is contained in:
30
.adonisrc.json
Normal file
30
.adonisrc.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"typescript": true,
|
||||
"commands": [
|
||||
"./commands",
|
||||
"@adonisjs/core/build/commands",
|
||||
"@adonisjs/repl/build/commands",
|
||||
"@adonisjs/lucid/build/commands"
|
||||
],
|
||||
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
||||
"aliases": {
|
||||
"App": "app",
|
||||
"Config": "config",
|
||||
"Database": "database",
|
||||
"Contracts": "contracts"
|
||||
},
|
||||
"preloads": [
|
||||
"./start/routes",
|
||||
"./start/kernel"
|
||||
],
|
||||
"providers": [
|
||||
"./providers/AppProvider",
|
||||
"@adonisjs/core",
|
||||
"@adonisjs/auth",
|
||||
"@adonisjs/redis",
|
||||
"@adonisjs/lucid"
|
||||
],
|
||||
"aceProviders": [
|
||||
"@adonisjs/repl"
|
||||
]
|
||||
}
|
||||
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.json]
|
||||
insert_final_newline = ignore
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
14
.env.example
Normal file
14
.env.example
Normal file
@@ -0,0 +1,14 @@
|
||||
PORT=
|
||||
HOST=
|
||||
NODE_ENV=
|
||||
APP_KEY=
|
||||
REDIS_CONNECTION=
|
||||
REDIS_HOST=
|
||||
REDIS_PORT=
|
||||
REDIS_PASSWORD=
|
||||
DB_CONNECTION=
|
||||
MYSQL_HOST=
|
||||
MYSQL_PORT=
|
||||
MYSQL_USER=
|
||||
MYSQL_PASSWORD=
|
||||
MYSQL_DB_NAME=
|
||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
build
|
||||
coverage
|
||||
.vscode
|
||||
.DS_STORE
|
||||
.env
|
||||
tmp
|
||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
12
.idea/artclick.iml
generated
Normal file
12
.idea/artclick.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/discord.xml
generated
Normal file
6
.idea/discord.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/artclick.iml" filepath="$PROJECT_DIR$/.idea/artclick.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM node:15.8.0-alpine3.10
|
||||
|
||||
RUN mkdir -p /usr/src/artclick
|
||||
WORKDIR /usr/src/artclick
|
||||
|
||||
COPY . /usr/src/artclick
|
||||
|
||||
RUN apk update && \
|
||||
apk add git
|
||||
|
||||
RUN yarn install
|
||||
|
||||
RUN yarn build
|
||||
|
||||
RUN cp .env build
|
||||
|
||||
WORKDIR /usr/src/artclick/build
|
||||
|
||||
RUN yarn install --production
|
||||
|
||||
EXPOSE 1012
|
||||
|
||||
CMD ["yarn", "start"]
|
||||
16
ace
Normal file
16
ace
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Ace Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is the entry point for running ace commands.
|
||||
|
|
||||
*/
|
||||
|
||||
require('reflect-metadata')
|
||||
require('source-map-support').install({ handleUncaughtExceptions: false })
|
||||
|
||||
const { Ignitor } = require('@adonisjs/core/build/standalone')
|
||||
new Ignitor(__dirname)
|
||||
.ace()
|
||||
.handle(process.argv.slice(2))
|
||||
1
ace-manifest.json
Normal file
1
ace-manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
{"dump:rcfile":{"settings":{},"commandPath":"@adonisjs/core/build/commands/DumpRc","commandName":"dump:rcfile","description":"Dump contents of .adonisrc.json file along with defaults","args":[],"flags":[]},"list:routes":{"settings":{"loadApp":true},"commandPath":"@adonisjs/core/build/commands/ListRoutes","commandName":"list:routes","description":"List application routes","args":[],"flags":[{"name":"json","propertyName":"json","type":"boolean","description":"Output as JSON"}]},"generate:key":{"settings":{},"commandPath":"@adonisjs/core/build/commands/GenerateKey","commandName":"generate:key","description":"Generate a new APP_KEY secret","args":[],"flags":[]},"repl":{"settings":{"loadApp":true,"environment":"repl","stayAlive":true},"commandPath":"@adonisjs/repl/build/commands/AdonisRepl","commandName":"repl","description":"Start a new REPL session","args":[],"flags":[]},"db:seed":{"settings":{"loadApp":true},"commandPath":"@adonisjs/lucid/build/commands/DbSeed","commandName":"db:seed","description":"Execute database seeder files","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Define a custom database connection for the seeders","alias":"c"},{"name":"interactive","propertyName":"interactive","type":"boolean","description":"Run seeders in interactive mode","alias":"i"},{"name":"files","propertyName":"files","type":"array","description":"Define a custom set of seeders files names to run","alias":"f"}]},"make:model":{"settings":{},"commandPath":"@adonisjs/lucid/build/commands/MakeModel","commandName":"make:model","description":"Make a new Lucid model","args":[{"type":"string","propertyName":"name","name":"name","required":true,"description":"Name of the model class"}],"flags":[{"name":"migration","propertyName":"migration","type":"boolean","alias":"m","description":"Generate the migration for the model"},{"name":"controller","propertyName":"controller","type":"boolean","alias":"c","description":"Generate the controller for the model"}]},"make:migration":{"settings":{"loadApp":true},"commandPath":"@adonisjs/lucid/build/commands/MakeMigration","commandName":"make:migration","description":"Make a new migration file","args":[{"type":"string","propertyName":"name","name":"name","required":true,"description":"Name of the migration file"}],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Define a custom database connection for the migration"},{"name":"folder","propertyName":"folder","type":"string","description":"Pre-select a migration directory"},{"name":"create","propertyName":"create","type":"string","description":"Define the table name for creating a new table"},{"name":"table","propertyName":"table","type":"string","description":"Define the table name for altering an existing table"}]},"make:seeder":{"settings":{},"commandPath":"@adonisjs/lucid/build/commands/MakeSeeder","commandName":"make:seeder","description":"Make a new Seeder file","args":[{"type":"string","propertyName":"name","name":"name","required":true,"description":"Name of the seeder class"}],"flags":[]},"migration:run":{"settings":{"loadApp":true},"commandPath":"@adonisjs/lucid/build/commands/Migration/Run","commandName":"migration:run","description":"Run pending migrations","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Define a custom database connection","alias":"c"},{"name":"force","propertyName":"force","type":"boolean","description":"Explicitly force to run migrations in production"},{"name":"dry-run","propertyName":"dryRun","type":"boolean","description":"Print SQL queries, instead of running the migrations"}]},"migration:rollback":{"settings":{"loadApp":true},"commandPath":"@adonisjs/lucid/build/commands/Migration/Rollback","commandName":"migration:rollback","description":"Rollback migrations to a given batch number","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Define a custom database connection","alias":"c"},{"name":"force","propertyName":"force","type":"boolean","description":"Explictly force to run migrations in production"},{"name":"dry-run","propertyName":"dryRun","type":"boolean","description":"Print SQL queries, instead of running the migrations"},{"name":"batch","propertyName":"batch","type":"number","description":"Define custom batch number for rollback. Use 0 to rollback to initial state"}]},"migration:status":{"settings":{"loadApp":true},"commandPath":"@adonisjs/lucid/build/commands/Migration/Status","commandName":"migration:status","description":"Check migrations current status.","args":[],"flags":[{"name":"connection","propertyName":"connection","type":"string","description":"Define a custom database connection","alias":"c"}]}}
|
||||
62
app/Controllers/Http/LinksController.ts
Normal file
62
app/Controllers/Http/LinksController.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import {HttpContextContract} from '@ioc:Adonis/Core/HttpContext'
|
||||
import StoreValidator from "App/Validators/StoreValidator";
|
||||
import Link from "App/Models/Link";
|
||||
import UpdateValidator from "App/Validators/UpdateValidator";
|
||||
|
||||
export default class LinksController {
|
||||
|
||||
public async getLink ({params, response}: HttpContextContract) {
|
||||
const code = params.id
|
||||
const link = await Link.findByOrFail('code', code)
|
||||
|
||||
if (link.code === code) {
|
||||
let visitCount = link.visitCount
|
||||
await link.merge({
|
||||
visitCount: visitCount++
|
||||
}).save()
|
||||
return response.redirect(link.target)
|
||||
}
|
||||
return response.badRequest(`Code does not exist ! (/${code})`)
|
||||
}
|
||||
|
||||
public async getAllLinks ({response}: HttpContextContract) {
|
||||
const links = await Link.all()
|
||||
return response.ok(links);
|
||||
}
|
||||
|
||||
public async getVisitCount ({params}: HttpContextContract) {
|
||||
const code = params.id
|
||||
const link = await Link.findByOrFail('code', code)
|
||||
|
||||
//Check if code exists
|
||||
if (link.code === code) {
|
||||
return {
|
||||
count: link.visitCount
|
||||
}
|
||||
}
|
||||
return {
|
||||
message: `Code does not exist ! (${code}`
|
||||
}
|
||||
}
|
||||
|
||||
public async createLink ({request}: HttpContextContract) {
|
||||
const link = await Link.create(await request.validate(StoreValidator))
|
||||
return {
|
||||
message: `Link successfully created : ${link.code} + ${link.target}`
|
||||
}
|
||||
}
|
||||
|
||||
public async updateLink ({request}: HttpContextContract) {
|
||||
const link = await Link.findByOrFail('code', request.input('link'))
|
||||
const data = await request.validate(UpdateValidator)
|
||||
await link.merge(data).save()
|
||||
return link
|
||||
}
|
||||
|
||||
public async deleteLink ({request}: HttpContextContract) {
|
||||
const code = request.input('code')
|
||||
const link = await Link.findByOrFail('code', code)
|
||||
await link.delete()
|
||||
}
|
||||
|
||||
}
|
||||
27
app/Controllers/Http/UsersController.ts
Normal file
27
app/Controllers/Http/UsersController.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
|
||||
export default class UsersController {
|
||||
|
||||
public async login ({request, auth}: HttpContextContract) {
|
||||
const email = request.input('email')
|
||||
const password = request.input('password')
|
||||
|
||||
const token = await auth.use('api').attempt(email, password, {
|
||||
expiresIn: '2 days'
|
||||
})
|
||||
return token.toJSON()
|
||||
}
|
||||
|
||||
public async createInfiniteToken ({request, auth}: HttpContextContract) {
|
||||
const email = request.input('email')
|
||||
const password = request.input('password')
|
||||
const token = await auth.use('api').attempt(email, password)
|
||||
return token.toJSON()
|
||||
}
|
||||
|
||||
public async logout ({auth}: HttpContextContract) {
|
||||
await auth.use('api').logout()
|
||||
return { message: 'Vous avez été déconnecté' }
|
||||
}
|
||||
|
||||
}
|
||||
23
app/Exceptions/Handler.ts
Normal file
23
app/Exceptions/Handler.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Http Exception Handler
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| AdonisJs will forward all exceptions occurred during an HTTP request to
|
||||
| the following class. You can learn more about exception handling by
|
||||
| reading docs.
|
||||
|
|
||||
| The exception handler extends a base `HttpExceptionHandler` which is not
|
||||
| mandatory, however it can do lot of heavy lifting to handle the errors
|
||||
| properly.
|
||||
|
|
||||
*/
|
||||
|
||||
import Logger from '@ioc:Adonis/Core/Logger'
|
||||
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
|
||||
|
||||
export default class ExceptionHandler extends HttpExceptionHandler {
|
||||
constructor () {
|
||||
super(Logger)
|
||||
}
|
||||
}
|
||||
71
app/Middleware/Auth.ts
Normal file
71
app/Middleware/Auth.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
import { AuthenticationException } from '@adonisjs/auth/build/standalone'
|
||||
|
||||
/**
|
||||
* Auth middleware is meant to restrict un-authenticated access to a given route
|
||||
* or a group of routes.
|
||||
*
|
||||
* You must register this middleware inside `start/kernel.ts` file under the list
|
||||
* of named middleware.
|
||||
*/
|
||||
export default class AuthMiddleware {
|
||||
/**
|
||||
* The URL to redirect to when request is Unauthorized
|
||||
*/
|
||||
protected redirectTo = '/login'
|
||||
|
||||
/**
|
||||
* Authenticates the current HTTP request against a custom set of defined
|
||||
* guards.
|
||||
*
|
||||
* The authentication loop stops as soon as the user is authenticated using any
|
||||
* of the mentioned guards and that guard will be used by the rest of the code
|
||||
* during the current request.
|
||||
*/
|
||||
protected async authenticate (auth: HttpContextContract['auth'], guards: any[]) {
|
||||
/**
|
||||
* Hold reference to the guard last attempted within the for loop. We pass
|
||||
* the reference of the guard to the "AuthenticationException", so that
|
||||
* it can decide the correct response behavior based upon the guard
|
||||
* driver
|
||||
*/
|
||||
let guardLastAttempted: string | undefined
|
||||
|
||||
for (let guard of guards) {
|
||||
guardLastAttempted = guard
|
||||
|
||||
if (await auth.use(guard).check()) {
|
||||
/**
|
||||
* Instruct auth to use the given guard as the default guard for
|
||||
* the rest of the request, since the user authenticated
|
||||
* succeeded here
|
||||
*/
|
||||
auth.defaultGuard = guard
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unable to authenticate using any guard
|
||||
*/
|
||||
throw new AuthenticationException(
|
||||
'Unauthorized access',
|
||||
'E_UNAUTHORIZED_ACCESS',
|
||||
guardLastAttempted,
|
||||
this.redirectTo,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request
|
||||
*/
|
||||
public async handle ({ auth }: HttpContextContract, next: () => Promise<void>, customGuards: string[]) {
|
||||
/**
|
||||
* Uses the user defined guards or the default guard mentioned in
|
||||
* the config file
|
||||
*/
|
||||
const guards = customGuards.length ? customGuards : [auth.name]
|
||||
await this.authenticate(auth, guards)
|
||||
await next()
|
||||
}
|
||||
}
|
||||
21
app/Middleware/SilentAuth.ts
Normal file
21
app/Middleware/SilentAuth.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
|
||||
/**
|
||||
* Silent auth middleware can be used as a global middleware to silent check
|
||||
* if the user is logged-in or not.
|
||||
*
|
||||
* The request continues as usual, even when the user is not logged-in.
|
||||
*/
|
||||
export default class SilentAuthMiddleware {
|
||||
/**
|
||||
* Handle request
|
||||
*/
|
||||
public async handle ({ auth }: HttpContextContract, next: () => Promise<void>) {
|
||||
/**
|
||||
* Check if user is logged-in or not. If yes, then `ctx.auth.user` will be
|
||||
* set to the instance of the currently logged in user.
|
||||
*/
|
||||
await auth.check()
|
||||
await next()
|
||||
}
|
||||
}
|
||||
24
app/Models/Link.ts
Normal file
24
app/Models/Link.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
BaseModel, column,
|
||||
} from '@ioc:Adonis/Lucid/Orm'
|
||||
import {DateTime} from "luxon";
|
||||
|
||||
export default class Link extends BaseModel {
|
||||
@column({ isPrimary: true })
|
||||
public id: number
|
||||
|
||||
@column()
|
||||
public code: string;
|
||||
|
||||
@column()
|
||||
public target: string;
|
||||
|
||||
@column({columnName: 'visit_count'})
|
||||
public visitCount: number;
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime
|
||||
|
||||
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||
public updatedAt: DateTime
|
||||
}
|
||||
31
app/Models/User.ts
Normal file
31
app/Models/User.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { DateTime } from 'luxon'
|
||||
import Hash from '@ioc:Adonis/Core/Hash'
|
||||
import {
|
||||
column,
|
||||
beforeSave,
|
||||
BaseModel,
|
||||
} from '@ioc:Adonis/Lucid/Orm'
|
||||
|
||||
export default class User extends BaseModel {
|
||||
@column({ isPrimary: true })
|
||||
public id: number
|
||||
|
||||
@column()
|
||||
public email: string
|
||||
|
||||
@column({ serializeAs: null })
|
||||
public password: string
|
||||
|
||||
@column.dateTime({ autoCreate: true })
|
||||
public createdAt: DateTime
|
||||
|
||||
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
||||
public updatedAt: DateTime
|
||||
|
||||
@beforeSave()
|
||||
public static async hashPassword (user: User) {
|
||||
if (user.$dirty.password) {
|
||||
user.password = await Hash.make(user.password)
|
||||
}
|
||||
}
|
||||
}
|
||||
22
app/Validators/StoreValidator.ts
Normal file
22
app/Validators/StoreValidator.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
import {rules, schema} from '@ioc:Adonis/Core/Validator'
|
||||
|
||||
export default class StoreValidator {
|
||||
constructor (private ctx: HttpContextContract) {
|
||||
}
|
||||
|
||||
public schema = schema.create({
|
||||
code: schema.string({}, [
|
||||
rules.unique({table: 'links', column: 'code' }),
|
||||
rules.maxLength(10)
|
||||
]),
|
||||
target: schema.string({}),
|
||||
})
|
||||
|
||||
public cacheKey = this.ctx.routeKey
|
||||
|
||||
public messages = {
|
||||
'code.unique': 'The code already exist !',
|
||||
'code.maxLength': 'The code is too long ! (max 10 caracteres)'
|
||||
}
|
||||
}
|
||||
22
app/Validators/UpdateValidator.ts
Normal file
22
app/Validators/UpdateValidator.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
|
||||
import {rules, schema} from '@ioc:Adonis/Core/Validator'
|
||||
|
||||
export default class UpdateValidator {
|
||||
constructor (private ctx: HttpContextContract) {
|
||||
}
|
||||
|
||||
public schema = schema.create({
|
||||
code: schema.string.optional({}, [
|
||||
rules.unique({table: 'links', column: 'code' }),
|
||||
rules.maxLength(10)
|
||||
]),
|
||||
target: schema.string.optional({}),
|
||||
visit_count: schema.number.optional()
|
||||
})
|
||||
|
||||
|
||||
public cacheKey = this.ctx.routeKey
|
||||
|
||||
|
||||
public messages = {}
|
||||
}
|
||||
19
commands/index.ts
Normal file
19
commands/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { listDirectoryFiles } from '@adonisjs/core/build/standalone'
|
||||
import Application from '@ioc:Adonis/Core/Application'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exporting an array of commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Instead of manually exporting each file from this directory, we use the
|
||||
| helper `listDirectoryFiles` to recursively collect and export an array
|
||||
| of filenames.
|
||||
|
|
||||
| Couple of things to note:
|
||||
|
|
||||
| 1. The file path must be relative from the project root and not this directory.
|
||||
| 2. We must ignore this file to avoid getting into an infinite loop
|
||||
|
|
||||
*/
|
||||
export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index'])
|
||||
235
config/app.ts
Normal file
235
config/app.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* Config source: https://git.io/JfefZ
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import proxyAddr from 'proxy-addr'
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import { ServerConfig } from '@ioc:Adonis/Core/Server'
|
||||
import { LoggerConfig } from '@ioc:Adonis/Core/Logger'
|
||||
import { ProfilerConfig } from '@ioc:Adonis/Core/Profiler'
|
||||
import { ValidatorConfig } from '@ioc:Adonis/Core/Validator'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application secret key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The secret to encrypt and sign different values in your application.
|
||||
| Make sure to keep the `APP_KEY` as an environment variable and secure.
|
||||
|
|
||||
| Note: Changing the application key for an existing app will make all
|
||||
| the cookies invalid and also the existing encrypted data will not
|
||||
| be decrypted.
|
||||
|
|
||||
*/
|
||||
export const appKey: string = Env.get('APP_KEY')
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Http server configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The configuration for the HTTP(s) server. Make sure to go through all
|
||||
| the config properties to make keep server secure.
|
||||
|
|
||||
*/
|
||||
export const http: ServerConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allow method spoofing
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Method spoofing enables defining custom HTTP methods using a query string
|
||||
| `_method`. This is usually required when you are making traditional
|
||||
| form requests and wants to use HTTP verbs like `PUT`, `DELETE` and
|
||||
| so on.
|
||||
|
|
||||
*/
|
||||
allowMethodSpoofing: false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Subdomain offset
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
subdomainOffset: 2,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Request Ids
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to `true` will generate a unique request id for each
|
||||
| HTTP request and set it as `x-request-id` header.
|
||||
|
|
||||
*/
|
||||
generateRequestId: false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Trusting proxy servers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define the proxy servers that AdonisJs must trust for reading `X-Forwarded`
|
||||
| headers.
|
||||
|
|
||||
*/
|
||||
trustProxy: proxyAddr.compile('loopback'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Generating Etag
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Whether or not to generate an etag for every response.
|
||||
|
|
||||
*/
|
||||
etag: false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JSONP Callback
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
jsonpCallbackName: 'callback',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookie settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
cookie: {
|
||||
domain: '',
|
||||
path: '/',
|
||||
maxAge: '2h',
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
sameSite: false,
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Force content negotiation to JSON
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The internals of the framework relies on the content negotiation to
|
||||
| detect the best possible response type for a given HTTP request.
|
||||
|
|
||||
| However, it is a very common these days that API servers always wants to
|
||||
| make response in JSON regardless of the existence of the `Accept` header.
|
||||
|
|
||||
| By setting `forceContentNegotiationToJSON = true`, you negotiate with the
|
||||
| server in advance to always return JSON without relying on the client
|
||||
| to set the header explicitly.
|
||||
|
|
||||
*/
|
||||
forceContentNegotiationToJSON: true,
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logger
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export const logger: LoggerConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The name of the application you want to add to the log. It is recommended
|
||||
| to always have app name in every log line.
|
||||
|
|
||||
| The `APP_NAME` environment variable is automatically set by AdonisJS by
|
||||
| reading the `name` property from the `package.json` file.
|
||||
|
|
||||
*/
|
||||
name: Env.get('APP_NAME'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Toggle logger
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable or disable logger application wide
|
||||
|
|
||||
*/
|
||||
enabled: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logging level
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The level from which you want the logger to flush logs. It is recommended
|
||||
| to make use of the environment variable, so that you can define log levels
|
||||
| at deployment level and not code level.
|
||||
|
|
||||
*/
|
||||
level: Env.get('LOG_LEVEL', 'info'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pretty print
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| It is highly advised NOT to use `prettyPrint` in production, since it
|
||||
| can have huge impact on performance.
|
||||
|
|
||||
*/
|
||||
prettyPrint: Env.get('NODE_ENV') === 'development',
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Profiler
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export const profiler: ProfilerConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Toggle profiler
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable or disable profiler
|
||||
|
|
||||
*/
|
||||
enabled: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Blacklist actions/row labels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define an array of actions or row labels that you want to disable from
|
||||
| getting profiled.
|
||||
|
|
||||
*/
|
||||
blacklist: [],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Whitelist actions/row labels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define an array of actions or row labels that you want to whitelist for
|
||||
| the profiler. When whitelist is defined, then `blacklist` is ignored.
|
||||
|
|
||||
*/
|
||||
whitelist: [],
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validator
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configure the global configuration for the validator. Here's the reference
|
||||
| to the default config https://git.io/JT0WE
|
||||
|
|
||||
*/
|
||||
export const validator: ValidatorConfig = {
|
||||
}
|
||||
111
config/auth.ts
Normal file
111
config/auth.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Config source: https://git.io/JvyKy
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import { AuthConfig } from '@ioc:Adonis/Addons/Auth'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Mapping
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| List of available authentication mapping. You must first define them
|
||||
| inside the `contracts/auth.ts` file before mentioning them here.
|
||||
|
|
||||
*/
|
||||
const authConfig: AuthConfig = {
|
||||
guard: 'api',
|
||||
list: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| OAT Guard
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| OAT (Opaque access tokens) guard uses database backed tokens to authenticate
|
||||
| HTTP request. This guard DOES NOT rely on sessions or cookies and uses
|
||||
| Authorization header value for authentication.
|
||||
|
|
||||
| Use this guard to authenticate mobile apps or web clients that cannot rely
|
||||
| on cookies/sessions.
|
||||
|
|
||||
*/
|
||||
api: {
|
||||
driver: 'oat',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis provider for managing tokens
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Uses Redis for managing tokens. We recommend using the "redis" driver
|
||||
| over the "database" driver when the tokens based auth is the
|
||||
| primary authentication mode.
|
||||
|
|
||||
| Redis ensure that all the expired tokens gets cleaned up automatically.
|
||||
| Whereas with SQL, you have to cleanup expired tokens manually.
|
||||
|
|
||||
| The foreignKey column is used to make the relationship between the user
|
||||
| and the token. You are free to use any column name here.
|
||||
|
|
||||
*/
|
||||
tokenProvider: {
|
||||
driver: 'redis',
|
||||
redisConnection: 'local',
|
||||
foreignKey: 'user_id',
|
||||
},
|
||||
|
||||
provider: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Name of the driver
|
||||
|
|
||||
*/
|
||||
driver: 'lucid',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Identifier key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The identifier key is the unique key on the model. In most cases specifying
|
||||
| the primary key is the right choice.
|
||||
|
|
||||
*/
|
||||
identifierKey: 'id',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Uids
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Uids are used to search a user against one of the mentioned columns. During
|
||||
| login, the auth module will search the user mentioned value against one
|
||||
| of the mentioned columns to find their user record.
|
||||
|
|
||||
*/
|
||||
uids: ['email'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Model
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The model to use for fetching or finding users. The model is imported
|
||||
| lazily since the config files are read way earlier in the lifecycle
|
||||
| of booting the app and the models may not be in a usable state at
|
||||
| that time.
|
||||
|
|
||||
*/
|
||||
model: () => import('App/Models/User'),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default authConfig
|
||||
186
config/bodyparser.ts
Normal file
186
config/bodyparser.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Config source: https://git.io/Jfefn
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import { BodyParserConfig } from '@ioc:Adonis/Core/BodyParser'
|
||||
|
||||
const bodyParserConfig: BodyParserConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| White listed methods
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| HTTP methods for which body parsing must be performed. It is a good practice
|
||||
| to avoid body parsing for `GET` requests.
|
||||
|
|
||||
*/
|
||||
whitelistedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| JSON parser settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The settings for the JSON parser. The types defines the request content
|
||||
| types which gets processed by the JSON parser.
|
||||
|
|
||||
*/
|
||||
json: {
|
||||
encoding: 'utf-8',
|
||||
limit: '1mb',
|
||||
strict: true,
|
||||
types: [
|
||||
'application/json',
|
||||
'application/json-patch+json',
|
||||
'application/vnd.api+json',
|
||||
'application/csp-report',
|
||||
],
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Form parser settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The settings for the `application/x-www-form-urlencoded` parser. The types
|
||||
| defines the request content types which gets processed by the form parser.
|
||||
|
|
||||
*/
|
||||
form: {
|
||||
encoding: 'utf-8',
|
||||
limit: '1mb',
|
||||
queryString: {},
|
||||
types: [
|
||||
'application/x-www-form-urlencoded',
|
||||
],
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Raw body parser settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Raw body just reads the request body stream as a plain text, which you
|
||||
| can process by hand. This must be used when request body type is not
|
||||
| supported by the body parser.
|
||||
|
|
||||
*/
|
||||
raw: {
|
||||
encoding: 'utf-8',
|
||||
limit: '1mb',
|
||||
queryString: {},
|
||||
types: [
|
||||
'text/*',
|
||||
],
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Multipart parser settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The settings for the `multipart/form-data` parser. The types defines the
|
||||
| request content types which gets processed by the form parser.
|
||||
|
|
||||
*/
|
||||
multipart: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto process
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The auto process option will process uploaded files and writes them to
|
||||
| the `tmp` folder. You can turn it off and then manually use the stream
|
||||
| to pipe stream to a different destination.
|
||||
|
|
||||
| It is recommended to keep `autoProcess=true`. Unless you are processing bigger
|
||||
| file sizes.
|
||||
|
|
||||
*/
|
||||
autoProcess: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Files to be processed manually
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can turn off `autoProcess` for certain routes by defining
|
||||
| routes inside the following array.
|
||||
|
|
||||
| NOTE: Make sure the route pattern starts with a leading slash.
|
||||
|
|
||||
| Correct
|
||||
| ```js
|
||||
| /projects/:id/file
|
||||
| ```
|
||||
|
|
||||
| Incorrect
|
||||
| ```js
|
||||
| projects/:id/file
|
||||
| ```
|
||||
*/
|
||||
processManually: [],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Temporary file name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When auto processing is on. We will use this method to compute the temporary
|
||||
| file name. AdonisJs will compute a unique `tmpPath` for you automatically,
|
||||
| However, you can also define your own custom method.
|
||||
|
|
||||
*/
|
||||
// tmpFileName () {
|
||||
// },
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encoding
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Request body encoding
|
||||
|
|
||||
*/
|
||||
encoding: 'utf-8',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Max Fields
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The maximum number of fields allowed in the request body. The field includes
|
||||
| text inputs and files both.
|
||||
|
|
||||
*/
|
||||
maxFields: 1000,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Request body limit
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The total limit to the multipart body. This includes all request files
|
||||
| and fields data.
|
||||
|
|
||||
*/
|
||||
limit: '20mb',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Types
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The types that will be considered and parsed as multipart body.
|
||||
|
|
||||
*/
|
||||
types: [
|
||||
'multipart/form-data',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export default bodyParserConfig
|
||||
134
config/cors.ts
Normal file
134
config/cors.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Config source: https://git.io/JfefC
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import { CorsConfig } from '@ioc:Adonis/Core/Cors'
|
||||
|
||||
const corsConfig: CorsConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enabled
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A boolean to enable or disable CORS integration from your AdonisJs
|
||||
| application.
|
||||
|
|
||||
| Setting the value to `true` will enable the CORS for all HTTP request. However,
|
||||
| you can define a function to enable/disable it on per request basis as well.
|
||||
|
|
||||
*/
|
||||
enabled: true,
|
||||
|
||||
// You can also use a function that return true or false.
|
||||
// enabled: (request) => request.url().startsWith('/api')
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Origin
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set a list of origins to be allowed for `Access-Control-Allow-Origin`.
|
||||
| The value can be one of the following:
|
||||
|
|
||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
|
|
||||
| Boolean (true) - Allow current request origin.
|
||||
| Boolean (false) - Disallow all.
|
||||
| String - Comma separated list of allowed origins.
|
||||
| Array - An array of allowed origins.
|
||||
| String (*) - A wildcard (*) to allow all request origins.
|
||||
| Function - Receives the current origin string and should return
|
||||
| one of the above values.
|
||||
|
|
||||
*/
|
||||
origin: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Methods
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of allowed HTTP methods for CORS. The `Access-Control-Request-Method`
|
||||
| is checked against the following list.
|
||||
|
|
||||
| Following is the list of default methods. Feel free to add more.
|
||||
*/
|
||||
methods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Headers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| List of headers to be allowed for `Access-Control-Allow-Headers` header.
|
||||
| The value can be one of the following:
|
||||
|
|
||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers
|
||||
|
|
||||
| Boolean(true) - Allow all headers mentioned in `Access-Control-Request-Headers`.
|
||||
| Boolean(false) - Disallow all headers.
|
||||
| String - Comma separated list of allowed headers.
|
||||
| Array - An array of allowed headers.
|
||||
| Function - Receives the current header and should return one of the above values.
|
||||
|
|
||||
*/
|
||||
headers: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expose Headers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| A list of headers to be exposed by setting `Access-Control-Expose-Headers`.
|
||||
| header. By default following 6 simple response headers are exposed.
|
||||
|
|
||||
| Cache-Control
|
||||
| Content-Language
|
||||
| Content-Type
|
||||
| Expires
|
||||
| Last-Modified
|
||||
| Pragma
|
||||
|
|
||||
| In order to add more headers, simply define them inside the following array.
|
||||
|
|
||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
|
||||
|
|
||||
*/
|
||||
exposeHeaders: [
|
||||
'cache-control',
|
||||
'content-language',
|
||||
'content-type',
|
||||
'expires',
|
||||
'last-modified',
|
||||
'pragma',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Credentials
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Toggle `Access-Control-Allow-Credentials` header. If value is set to `true`,
|
||||
| then header will be set, otherwise not.
|
||||
|
|
||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
|
|
||||
*/
|
||||
credentials: true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| MaxAge
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define `Access-Control-Max-Age` header in seconds.
|
||||
| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
|
|
||||
*/
|
||||
maxAge: 90,
|
||||
}
|
||||
|
||||
export default corsConfig
|
||||
68
config/database.ts
Normal file
68
config/database.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Config source: https://git.io/JesV9
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import { OrmConfig } from '@ioc:Adonis/Lucid/Orm'
|
||||
import { DatabaseConfig } from '@ioc:Adonis/Lucid/Database'
|
||||
|
||||
const databaseConfig: DatabaseConfig & { orm: Partial<OrmConfig> } = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The primary connection for making database queries across the application
|
||||
| You can use any key from the `connections` object defined in this same
|
||||
| file.
|
||||
|
|
||||
*/
|
||||
connection: Env.get('DB_CONNECTION'),
|
||||
|
||||
connections: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| MySQL config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Configuration for MySQL database. Make sure to install the driver
|
||||
| from npm when using this connection
|
||||
|
|
||||
| npm i mysql
|
||||
|
|
||||
*/
|
||||
mysql: {
|
||||
client: 'mysql',
|
||||
connection: {
|
||||
host: Env.get('MYSQL_HOST'),
|
||||
port: Env.get('MYSQL_PORT'),
|
||||
user: Env.get('MYSQL_USER'),
|
||||
password: Env.get('MYSQL_PASSWORD', ''),
|
||||
database: Env.get('MYSQL_DB_NAME'),
|
||||
},
|
||||
healthCheck: true,
|
||||
debug: false,
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ORM Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Following are some of the configuration options to tweak the conventional
|
||||
| settings of the ORM. For example:
|
||||
|
|
||||
| - Define a custom function to compute the default table name for a given model.
|
||||
| - Or define a custom function to compute the primary key for a given model.
|
||||
|
|
||||
*/
|
||||
orm: {
|
||||
},
|
||||
}
|
||||
|
||||
export default databaseConfig
|
||||
75
config/hash.ts
Normal file
75
config/hash.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Config source: https://git.io/JfefW
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import { HashConfig } from '@ioc:Adonis/Core/Hash'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Hash Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The `HashConfig` relies on the `HashList` interface which is
|
||||
| defined inside `contracts` directory.
|
||||
|
|
||||
*/
|
||||
const hashConfig: HashConfig = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default hasher
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default we make use of the bcrypt hasher to hash values. However, feel
|
||||
| free to change the default value
|
||||
|
|
||||
*/
|
||||
default: Env.get('HASH_DRIVER', 'argon'),
|
||||
|
||||
list: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Argon
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Argon mapping uses the `argon2` driver to hash values.
|
||||
|
|
||||
| Make sure you install the underlying dependency for this driver to work.
|
||||
| https://www.npmjs.com/package/phc-argon2.
|
||||
|
|
||||
| npm install phc-argon2
|
||||
|
|
||||
*/
|
||||
argon: {
|
||||
driver: 'argon2',
|
||||
variant: 'id',
|
||||
iterations: 3,
|
||||
memory: 4096,
|
||||
parallelism: 1,
|
||||
saltSize: 16,
|
||||
},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bcrypt
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Bcrypt mapping uses the `bcrypt` driver to hash values.
|
||||
|
|
||||
| Make sure you install the underlying dependency for this driver to work.
|
||||
| https://www.npmjs.com/package/phc-bcrypt.
|
||||
|
|
||||
| npm install phc-bcrypt
|
||||
|
|
||||
*/
|
||||
bcrypt: {
|
||||
driver: 'bcrypt',
|
||||
rounds: 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default hashConfig
|
||||
49
config/redis.ts
Normal file
49
config/redis.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Config source: https://git.io/JemcF
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import { RedisConfig } from '@ioc:Adonis/Addons/Redis'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Following is the configuration used by the Redis provider to connect to
|
||||
| the redis server and execute redis commands.
|
||||
|
|
||||
| Do make sure to pre-define the connections type inside `contracts/redis.ts`
|
||||
| file for AdonisJs to recognize connections.
|
||||
|
|
||||
| Make sure to check `contracts/redis.ts` file for defining extra connections
|
||||
*/
|
||||
const redisConfig: RedisConfig = {
|
||||
connection: Env.get('REDIS_CONNECTION'),
|
||||
|
||||
connections: {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The default connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The main connection you want to use to execute redis commands. The same
|
||||
| connection will be used by the session provider, if you rely on the
|
||||
| redis driver.
|
||||
|
|
||||
*/
|
||||
local: {
|
||||
host: Env.get('REDIS_HOST'),
|
||||
port: Env.get('REDIS_PORT'),
|
||||
password: Env.get('REDIS_PASSWORD', ''),
|
||||
db: 0,
|
||||
keyPrefix: 'artclick:',
|
||||
healthCheck: true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default redisConfig
|
||||
73
contracts/auth.ts
Normal file
73
contracts/auth.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Contract source: https://git.io/JvyKD
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this
|
||||
* file.
|
||||
*/
|
||||
|
||||
import User from 'App/Models/User'
|
||||
|
||||
declare module '@ioc:Adonis/Addons/Auth' {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The providers are used to fetch users. The Auth module comes pre-bundled
|
||||
| with two providers that are `Lucid` and `Database`. Both uses database
|
||||
| to fetch user details.
|
||||
|
|
||||
| You can also create and register your own custom providers.
|
||||
|
|
||||
*/
|
||||
interface ProvidersList {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Provider
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following provider uses Lucid models as a driver for fetching user
|
||||
| details from the database for authentication.
|
||||
|
|
||||
| You can create multiple providers using the same underlying driver with
|
||||
| different Lucid models.
|
||||
|
|
||||
*/
|
||||
user: {
|
||||
implementation: LucidProviderContract<typeof User>,
|
||||
config: LucidProviderConfig<typeof User>,
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The guards are used for authenticating users using different drivers.
|
||||
| The auth module comes with 4 different guards.
|
||||
|
|
||||
| - SessionGuardContract
|
||||
| - BasicAuthGuardContract
|
||||
| - JwtGuardContract
|
||||
| - OATGuardContract ( Opaque access token )
|
||||
|
|
||||
| Every guard needs a provider for looking up users from the database.
|
||||
|
|
||||
*/
|
||||
interface GuardsList {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| OAT Guard
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| OAT, stands for (Opaque access tokens) guard uses database backed tokens
|
||||
| to authenticate requests.
|
||||
|
|
||||
*/
|
||||
api: {
|
||||
implementation: OATGuardContract<'user', 'api'>,
|
||||
config: OATGuardConfig<'user'>,
|
||||
},
|
||||
}
|
||||
}
|
||||
24
contracts/env.ts
Normal file
24
contracts/env.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Contract source: https://git.io/JTm6U
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this contract
|
||||
* file.
|
||||
*/
|
||||
|
||||
declare module '@ioc:Adonis/Core/Env' {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Getting types for validated environment variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The `default` export from the "../env.ts" file exports types for the
|
||||
| validated environment variables. Here we merge them with the `EnvTypes`
|
||||
| interface so that you can enjoy intellisense when using the "Env"
|
||||
| module.
|
||||
|
|
||||
*/
|
||||
|
||||
type CustomTypes = typeof import("../env").default;
|
||||
interface EnvTypes extends CustomTypes {
|
||||
}
|
||||
}
|
||||
30
contracts/events.ts
Normal file
30
contracts/events.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Contract source: https://git.io/JfefG
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this contract
|
||||
* file.
|
||||
*/
|
||||
|
||||
declare module '@ioc:Adonis/Core/Event' {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Define typed events
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can define types for events inside the following interface and
|
||||
| AdonisJS will make sure that all listeners and emit calls adheres
|
||||
| to the defined types.
|
||||
|
|
||||
| For example:
|
||||
|
|
||||
| interface EventsList {
|
||||
| 'new:user': UserModel
|
||||
| }
|
||||
|
|
||||
| Now calling `Event.emit('new:user')` will statically ensure that passed value is
|
||||
| an instance of the the UserModel only.
|
||||
|
|
||||
*/
|
||||
interface EventsList {
|
||||
}
|
||||
}
|
||||
21
contracts/hash.ts
Normal file
21
contracts/hash.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Contract source: https://git.io/Jfefs
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this contract
|
||||
* file.
|
||||
*/
|
||||
|
||||
declare module '@ioc:Adonis/Core/Hash' {
|
||||
import { HashDrivers } from '@ioc:Adonis/Core/Hash'
|
||||
|
||||
interface HashersList {
|
||||
bcrypt: {
|
||||
config: BcryptConfig,
|
||||
implementation: BcryptContract,
|
||||
},
|
||||
argon: {
|
||||
config: ArgonConfig,
|
||||
implementation: ArgonContract,
|
||||
},
|
||||
}
|
||||
}
|
||||
12
contracts/redis.ts
Normal file
12
contracts/redis.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Contract source: https://git.io/JemcN
|
||||
*
|
||||
* Feel free to let us know via PR, if you find something broken in this config
|
||||
* file.
|
||||
*/
|
||||
|
||||
declare module '@ioc:Adonis/Addons/Redis' {
|
||||
interface RedisConnectionsList {
|
||||
local: RedisConnectionConfig,
|
||||
}
|
||||
}
|
||||
1
database/factories/index.ts
Normal file
1
database/factories/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
// import Factory from '@ioc:Adonis/Lucid/Factory'
|
||||
18
database/migrations/1587988332388_users.ts
Normal file
18
database/migrations/1587988332388_users.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
|
||||
|
||||
export default class UsersSchema extends BaseSchema {
|
||||
protected tableName = 'users'
|
||||
|
||||
public async up () {
|
||||
this.schema.createTable(this.tableName, (table) => {
|
||||
table.increments('id').primary()
|
||||
table.string('email', 255).notNullable()
|
||||
table.string('password', 180).notNullable()
|
||||
table.timestamps(true)
|
||||
})
|
||||
}
|
||||
|
||||
public async down () {
|
||||
this.schema.dropTable(this.tableName)
|
||||
}
|
||||
}
|
||||
19
database/migrations/1618757695309_links.ts
Normal file
19
database/migrations/1618757695309_links.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
|
||||
|
||||
export default class Links extends BaseSchema {
|
||||
protected tableName = 'links'
|
||||
|
||||
public async up () {
|
||||
this.schema.createTable(this.tableName, (table) => {
|
||||
table.increments('id')
|
||||
table.string('code').notNullable()
|
||||
table.string('target').notNullable()
|
||||
table.integer('visit_count').defaultTo(0)
|
||||
table.timestamps(true)
|
||||
})
|
||||
}
|
||||
|
||||
public async down () {
|
||||
this.schema.dropTable(this.tableName)
|
||||
}
|
||||
}
|
||||
34
env.ts
Normal file
34
env.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validating Environment Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| In this file we define the rules for validating environment variables.
|
||||
| By performing validation we ensure that your application is running in
|
||||
| a stable environment with correct configuration values.
|
||||
|
|
||||
| This file is read automatically by the framework during the boot lifecycle
|
||||
| and hence do not rename or move this file to a different location.
|
||||
|
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
|
||||
export default Env.rules({
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
APP_NAME: Env.schema.string(),
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'testing'] as const),
|
||||
|
||||
REDIS_CONNECTION: Env.schema.enum(['local'] as const),
|
||||
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
||||
REDIS_PORT: Env.schema.number(),
|
||||
REDIS_PASSWORD: Env.schema.string.optional(),
|
||||
|
||||
MYSQL_HOST: Env.schema.string({ format: 'host' }),
|
||||
MYSQL_PORT: Env.schema.number(),
|
||||
MYSQL_USER: Env.schema.string(),
|
||||
MYSQL_PASSWORD: Env.schema.string.optional(),
|
||||
MYSQL_DB_NAME: Env.schema.string(),
|
||||
})
|
||||
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "artclick",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node ace build --production",
|
||||
"start": "node server.js",
|
||||
"dev": "node ace serve --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@adonisjs/assembler": "^3.0.0",
|
||||
"adonis-preset-ts": "^2.1.0",
|
||||
"pino-pretty": "^4.7.1",
|
||||
"typescript": "~4.1",
|
||||
"youch": "^2.2.1",
|
||||
"youch-terminal": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adonisjs/auth": "^5.1.1",
|
||||
"@adonisjs/core": "~5.0.4-preview-rc",
|
||||
"@adonisjs/lucid": "^10.0.0",
|
||||
"@adonisjs/redis": "^5.0.9",
|
||||
"@adonisjs/repl": "^1.0.0",
|
||||
"luxon": "^1.26.0",
|
||||
"mysql": "^2.18.1",
|
||||
"proxy-addr": "^2.0.6",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"source-map-support": "^0.5.19"
|
||||
}
|
||||
}
|
||||
24
providers/AppProvider.ts
Normal file
24
providers/AppProvider.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ApplicationContract } from '@ioc:Adonis/Core/Application'
|
||||
|
||||
export default class AppProvider {
|
||||
public static needsApplication = true
|
||||
|
||||
constructor (protected app: ApplicationContract) {
|
||||
}
|
||||
|
||||
public register () {
|
||||
// Register your own bindings
|
||||
}
|
||||
|
||||
public async boot () {
|
||||
// IoC container is ready
|
||||
}
|
||||
|
||||
public async ready () {
|
||||
// App is ready
|
||||
}
|
||||
|
||||
public async shutdown () {
|
||||
// Cleanup, since app is going down
|
||||
}
|
||||
}
|
||||
21
server.ts
Normal file
21
server.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| AdonisJs Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The contents in this file is meant to bootstrap the AdonisJs application
|
||||
| and start the HTTP server to accept incoming connections. You must avoid
|
||||
| making this file dirty and instead make use of `lifecycle hooks` provided
|
||||
| by AdonisJs service providers for custom code.
|
||||
|
|
||||
*/
|
||||
|
||||
import 'reflect-metadata'
|
||||
import sourceMapSupport from 'source-map-support'
|
||||
import { Ignitor } from '@adonisjs/core/build/standalone'
|
||||
|
||||
sourceMapSupport.install({ handleUncaughtExceptions: false })
|
||||
|
||||
new Ignitor(__dirname)
|
||||
.httpServer()
|
||||
.start()
|
||||
46
start/kernel.ts
Normal file
46
start/kernel.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is used to define middleware for HTTP requests. You can register
|
||||
| middleware as a `closure` or an IoC container binding. The bindings are
|
||||
| preferred, since they keep this file clean.
|
||||
|
|
||||
*/
|
||||
|
||||
import Server from '@ioc:Adonis/Core/Server'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of global middleware, that will be executed in the order they
|
||||
| are defined for every HTTP requests.
|
||||
|
|
||||
*/
|
||||
Server.middleware.register([
|
||||
'Adonis/Core/BodyParserMiddleware',
|
||||
'App/Middleware/SilentAuth',
|
||||
])
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Named middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Named middleware are defined as key-value pair. The value is the namespace
|
||||
| or middleware function and key is the alias. Later you can use these
|
||||
| alias on individual routes. For example:
|
||||
|
|
||||
| { auth: 'App/Middleware/Auth' }
|
||||
|
|
||||
| and then use it as follows
|
||||
|
|
||||
| Route.get('dashboard', 'UserController.dashboard').middleware('auth')
|
||||
|
|
||||
*/
|
||||
Server.middleware.registerNamed({
|
||||
auth: 'App/Middleware/Auth',
|
||||
})
|
||||
47
start/routes.ts
Normal file
47
start/routes.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import Route from '@ioc:Adonis/Core/Route'
|
||||
import HealthCheck from "@ioc:Adonis/Core/HealthCheck";
|
||||
import {HttpContextContract} from "@ioc:Adonis/Core/HttpContext";
|
||||
|
||||
const BASE_URL = "https://go.arthurdanjou.fr"
|
||||
|
||||
Route.get('/', async ({response}: HttpContextContract) => {
|
||||
return response.status(200).send({
|
||||
domain: BASE_URL,
|
||||
version: "1.0",
|
||||
source: `${BASE_URL}/source`,
|
||||
healthCheck: `${BASE_URL}/health`,
|
||||
links: `${BASE_URL}/links`
|
||||
})
|
||||
})
|
||||
|
||||
Route.get('/source', async ({response}: HttpContextContract) => {
|
||||
return response.redirect('https://github.com/arthurdanjou/artclick')
|
||||
})
|
||||
|
||||
Route.get('health', async ({response}: HttpContextContract) => {
|
||||
const report = await HealthCheck.getReport()
|
||||
const isLive = await HealthCheck.isLive()
|
||||
const isReady = await HealthCheck.isReady()
|
||||
return report.healthy ? response.ok({ isLive, isReady, report: report.report }) : response.badRequest({ isLive, isReady, report: report.report })
|
||||
})
|
||||
|
||||
Route
|
||||
.group(() => {
|
||||
Route.post('/login', 'UsersController.login')
|
||||
Route.post('/logout', 'UsersController.logout')
|
||||
Route.post('/token', 'UsersController.createInfiniteToken')
|
||||
})
|
||||
.prefix('auth')
|
||||
|
||||
Route
|
||||
.group(() => {
|
||||
Route.post('/create', 'LinksController.createLink')
|
||||
Route.post('/update', 'LinksController.updateLink')
|
||||
Route.post('/delete', 'LinksController.deleteLink')
|
||||
})
|
||||
.prefix('options')
|
||||
.middleware('auth')
|
||||
|
||||
Route.get('/links', 'LinksController.getAllLinks') // --> Home
|
||||
Route.get('/:id', 'LinksController.getLink') // --> Go to target's code
|
||||
Route.get('/:id/count', 'LinksController.getVisitCount') // --> Get Visit count's code
|
||||
36
tsconfig.json
Normal file
36
tsconfig.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"extends": "./node_modules/adonis-preset-ts/tsconfig",
|
||||
"include": [
|
||||
"**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"outDir": "build",
|
||||
"rootDir": "./",
|
||||
"sourceMap": true,
|
||||
"paths": {
|
||||
"App/*": [
|
||||
"./app/*"
|
||||
],
|
||||
"Config/*": [
|
||||
"./config/*"
|
||||
],
|
||||
"Contracts/*": [
|
||||
"./contracts/*"
|
||||
],
|
||||
"Database/*": [
|
||||
"./database/*"
|
||||
]
|
||||
},
|
||||
"types": [
|
||||
"@adonisjs/core",
|
||||
"@adonisjs/repl",
|
||||
"@adonisjs/auth",
|
||||
"@adonisjs/redis",
|
||||
"@adonisjs/lucid"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user