diff --git a/app/Controllers/Http/LocationsController.ts b/app/Controllers/Http/LocationsController.ts index 5e3bcbd..9b2bc8d 100644 --- a/app/Controllers/Http/LocationsController.ts +++ b/app/Controllers/Http/LocationsController.ts @@ -1,6 +1,6 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' import Location from "App/Models/Location"; -import StoreValidator from "App/Validators/locations/StoreValidator"; +import LocationValidator from "App/Validators/location/LocationValidator"; export default class LocationsController { @@ -20,8 +20,8 @@ export default class LocationsController { }) } - public async set ({ request, response }: HttpContextContract) { - const data = await request.validate(StoreValidator) + public async add ({ request, response }: HttpContextContract) { + const data = await request.validate(LocationValidator) await Location.create(data) return response.status(200).send({ message: 'Location successfully added !' diff --git a/app/Controllers/Http/MeController.ts b/app/Controllers/Http/MeController.ts new file mode 100644 index 0000000..e385389 --- /dev/null +++ b/app/Controllers/Http/MeController.ts @@ -0,0 +1,47 @@ +import {HttpContextContract} from "@ioc:Adonis/Core/HttpContext"; + +export default class MeController { + + public me ({ response }: HttpContextContract) { + return response.status(200).send({ + pronouns: "Arthur", + home: ["Paris", "France"], + passions: [ + "Dev", + "DevOps", + "New technologies", + "Gaming" + ], + code: [ + "Javascript", + "Typescript", + "HTML", + "CSS", + "GoLang", + "Python", + "Java" + ], + askMeAbout: [ + "Web dev", + "Tech", + "Consulting", + "Cloud native", + "Software dev" + ], + technologies: { + webApp: ["VueJs", "NuxtJs", "Sass", "Tailwind"], + desktopApp: ["ElectronJs"], + mobileApp: ["React Native"], + backEnd: { + typescript: ["AdonisJs"], + java: ["Spring"] + }, + databases: ["MongoDB", "MariaDB", "Redis"], + messaging: ["RabbitMq"], + other: ["Docker", "Git"], + architecture: ["microservices", "event-driven", "design system pattern"], + operating_systems: ['Windows', 'Linux'] + }, + }) + } +} diff --git a/app/Controllers/Http/ProjectsController.ts b/app/Controllers/Http/ProjectsController.ts new file mode 100644 index 0000000..08b06d3 --- /dev/null +++ b/app/Controllers/Http/ProjectsController.ts @@ -0,0 +1,22 @@ +import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' +import Project from "App/Models/Project"; +import ProjectValidator from "App/Validators/project/ProjectValidator"; + +export default class ProjectsController { + + public async get ({ response }: HttpContextContract) { + const projects = await Project.query().orderBy('progress', 'desc') + return response.status(200).send({ + projects + }) + } + + public async add ({ request, response}: HttpContextContract) { + const data = await request.validate(ProjectValidator) + await Project.create(data) + return response.status(200).send({ + message: 'Project successfully created' + }) + } + +} diff --git a/app/Controllers/Http/StatsController.ts b/app/Controllers/Http/StatsController.ts index 877b2f5..e44af61 100644 --- a/app/Controllers/Http/StatsController.ts +++ b/app/Controllers/Http/StatsController.ts @@ -1,5 +1,5 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' -import {getTotalStats, getWeeklyStats, getMonthlyStats, getOtherStats, getDailyStats} from 'App/Helpers/StatsHelper' +import {getTotalStats, getWeeklyStats, getMonthlyStats, getDailyStats} from 'App/Helpers/StatsHelper' import DockerBuild from "App/Models/DockerBuild" import DockerCommand from "App/Models/DockerCommand" @@ -10,13 +10,11 @@ export default class StatsController { const weekly = await getWeeklyStats() const monthly = await getMonthlyStats() const total = await getTotalStats() - const other = await getOtherStats() return response.status(200).send({ daily: daily, weekly: weekly, monthly: monthly, total: total, - other : other }) } diff --git a/app/Helpers/StatsHelper.ts b/app/Helpers/StatsHelper.ts index 330a84e..87043c0 100644 --- a/app/Helpers/StatsHelper.ts +++ b/app/Helpers/StatsHelper.ts @@ -1,15 +1,11 @@ import DockerCommand from "App/Models/DockerCommand"; -import axios from "axios"; import DockerBuild from "App/Models/DockerBuild"; async function getDailyStats() { const commands = await DockerCommand.query().where('created_at', '>', new Date().getTime()) - const {data} = await axios.get('https://wakatime.com/api/v1/users/arthurdanjou/stats/last_7_days') const builds = await DockerBuild.query().where('created_at', '>', new Date().getTime()) - console.log('daily : ' + data.data) return { - development_hours: data.data[0].grand_total.total_seconds / 60 / 60, docker_commands_run: commands.length, docker_build_count: builds.length, } @@ -17,60 +13,33 @@ async function getDailyStats() { async function getWeeklyStats() { const commands = await DockerCommand.query().where('created_at', '>', new Date().getTime() - 1000 * 60 * 60 * 24 * 7) - const {data} = await axios.get('https://wakatime.com/api/v1/users/arthurdanjou/stats/last_7_days') const builds = await DockerBuild.query().where('created_at', '>', new Date().getTime() - 1000 * 60 * 60 * 24 * 7) - console.log('weekly : ' + data) return { - development_hours: data.data.total_seconds / 60 / 60, docker_commands_run: commands.length, docker_build_count: builds.length, - best_project: data.data.projects } } async function getMonthlyStats() { const commands = await DockerCommand.query().where('created_at', '>', new Date().getMonth() - 1) - const {data} = await axios.get('https://wakatime.com/api/v1/users/arthurdanjou/stats/last_30_days') const builds = await DockerBuild.query().where('created_at', '>', new Date().getMonth() - 1) - console.log('monthly : ' + data) return { - development_hours: data.data.total_seconds / 60 / 60, docker_commands_run: commands.length, docker_build_count: builds.length, - best_project: data.data.projects } } async function getTotalStats() { const commands = await DockerCommand.query() - const {data} = await axios.get('https://wakatime.com/api/v1/users/arthurdanjou/all_time_since_today') const builds = await DockerBuild.query() - console.log('total : ' + data) return { - development_hours: data.data.seconds, docker_commands_run: commands.length, docker_build_count: builds.length } } -async function getOtherStats() { - const {data} = await axios.get('https://wakatime.com/api/v1/users/arthurdanjou/stats/last_year') - console.log('other : ' + data) - return { - daily_average: data.data.daily_average / 60 / 60, - editors: [ - 'WebStorm', - 'Intellij Idea', - 'PyCharm', - 'GoLang', - 'DataGrip' - ], - operating_systems: 'Windows' - } -} - -export {getMonthlyStats, getTotalStats, getWeeklyStats, getOtherStats, getDailyStats} +export {getMonthlyStats, getTotalStats, getWeeklyStats, getDailyStats} diff --git a/app/Helpers/WakatimeLogger.ts b/app/Helpers/WakatimeLogger.ts deleted file mode 100644 index b3db090..0000000 --- a/app/Helpers/WakatimeLogger.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from "axios"; -import Env from '@ioc:Adonis/Core/Env' - -async function login() { - await axios.post("https://wakatime.com/oauth/token", - { - client_id: Env.get('WAKATIME_USERNAME'), - client_secret: Env.get('WAKATIME_PASSWORD') - }, - { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - }) -} - -export { login } diff --git a/app/Models/Project.ts b/app/Models/Project.ts new file mode 100644 index 0000000..041d0f6 --- /dev/null +++ b/app/Models/Project.ts @@ -0,0 +1,25 @@ +import { DateTime } from 'luxon' +import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm' + +export default class Project extends BaseModel { + @column({ isPrimary: true }) + public id: number + + @column() + public name: string + + @column() + public description: string + + @column() + public progress: number + + @column() + public url: string + + @column.dateTime({ autoCreate: true }) + public createdAt: DateTime + + @column.dateTime({ autoCreate: true, autoUpdate: true }) + public updatedAt: DateTime +} diff --git a/app/Validators/locations/StoreValidator.ts b/app/Validators/location/LocationValidator.ts similarity index 91% rename from app/Validators/locations/StoreValidator.ts rename to app/Validators/location/LocationValidator.ts index f46b62a..5b43f9e 100644 --- a/app/Validators/locations/StoreValidator.ts +++ b/app/Validators/location/LocationValidator.ts @@ -1,7 +1,7 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' import {schema} from '@ioc:Adonis/Core/Validator' -export default class StoreValidator { +export default class LocationValidator { constructor (private ctx: HttpContextContract) { } diff --git a/app/Validators/posts/StoreValidator.ts b/app/Validators/posts/StoreValidator.ts deleted file mode 100644 index c5c2b84..0000000 --- a/app/Validators/posts/StoreValidator.ts +++ /dev/null @@ -1,25 +0,0 @@ -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({ - title: schema.string(), - content: schema.string(), - description: schema.string(), - readingTime: schema.number(), - coverId: schema.number([rules.exists({ table: 'files', column: 'id' })]), - tags: schema.array().members( - schema.number() - ), - lightBackGround: schema.boolean() - }) - - public cacheKey = this.ctx.routeKey - - public messages = { - required: 'Le champ {{field}} doit être valide !', - } -} diff --git a/app/Validators/posts/UpdateValidator.ts b/app/Validators/posts/UpdateValidator.ts deleted file mode 100644 index c3a65e2..0000000 --- a/app/Validators/posts/UpdateValidator.ts +++ /dev/null @@ -1,25 +0,0 @@ -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({ - title: schema.string.optional(), - content: schema.string.optional(), - description: schema.string.optional(), - readingTime: schema.number.optional(), - coverId: schema.number.optional([rules.exists({ table: 'files', column: 'id' })]), - tags: schema.array.optional().members( - schema.number() - ), - lightBackGround: schema.boolean.optional() - }) - - public cacheKey = this.ctx.routeKey - - public messages = { - required: 'Le champ {{field}} doit être valide !' - } -} diff --git a/app/Validators/project/ProjectValidator.ts b/app/Validators/project/ProjectValidator.ts new file mode 100644 index 0000000..33fa214 --- /dev/null +++ b/app/Validators/project/ProjectValidator.ts @@ -0,0 +1,19 @@ +import { schema } from '@ioc:Adonis/Core/Validator' +import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' + +export default class ProjectValidator { + constructor (protected ctx: HttpContextContract) { + } + + public schema = schema.create({ + name: schema.string(), + description: schema.string(), + progress: schema.number(), + url: schema.string() + }) + + + public messages = { + required: 'Le champ {{field}} doit être valide !', + } +} diff --git a/app/tasks/GetDevelopmentHours.ts b/app/tasks/GetDevelopmentHours.ts deleted file mode 100644 index e69de29..0000000 diff --git a/app/tasks/LogDeezerHistory.ts b/app/tasks/LogDeezerHistory.ts deleted file mode 100644 index e69de29..0000000 diff --git a/database/migrations/1608409618132_deezer_songs.ts b/database/migrations/1608409618132_deezer_songs.ts deleted file mode 100644 index f14f6a0..0000000 --- a/database/migrations/1608409618132_deezer_songs.ts +++ /dev/null @@ -1,23 +0,0 @@ -import BaseSchema from '@ioc:Adonis/Lucid/Schema' - -export default class DeezerSongs extends BaseSchema { - protected tableName = 'deezer_songs' - - public async up () { - this.schema.createTable(this.tableName, (table) => { - table.increments('id') - table.string('author') - table.string('title') - table.string('album') - table.string('type') - table.string('device') - table.integer('duration') - table.date('release_date') - table.timestamps(true) - }) - } - - public async down () { - this.schema.dropTable(this.tableName) - } -} diff --git a/database/migrations/1608415261417_projects.ts b/database/migrations/1608415261417_projects.ts new file mode 100644 index 0000000..08b29cf --- /dev/null +++ b/database/migrations/1608415261417_projects.ts @@ -0,0 +1,20 @@ +import BaseSchema from '@ioc:Adonis/Lucid/Schema' + +export default class Projects extends BaseSchema { + protected tableName = 'projects' + + public async up () { + this.schema.createTable(this.tableName, (table) => { + table.increments('id').primary() + table.string('name') + table.string('description') + table.string('url') + table.integer('progress') + table.timestamps(true) + }) + } + + public async down () { + this.schema.dropTable(this.tableName) + } +} diff --git a/start/routes.ts b/start/routes.ts index 7d294ab..20cebe3 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -5,66 +5,63 @@ import HealthCheck from "@ioc:Adonis/Core/HealthCheck"; const BASE_URL = "https://api.arthurdanjou.fr" -Route.get('/health', async ({ response }) => { - const report = await HealthCheck.getReport() - return report.healthy ? response.ok(report) : response.badRequest(report) -}) - Route.get('/', async ({response}: HttpContextContract) => { - response.status(200).send({ + return response.status(200).send({ domain: BASE_URL, version: "1.0", source: `${BASE_URL}/source`, + healthCheck: `${BASE_URL}/health`, routes: { - deezer_data: `${BASE_URL}/deezer`, + arthur_data: `${BASE_URL}/me`, stats_data: `${BASE_URL}/stats`, - state_data: `${BASE_URL}/state`, - locations_data: `${BASE_URL}/location`, - locations_history: `${BASE_URL}/location/history`, - health: `${BASE_URL}/health` - } + state_data: `${BASE_URL}/states`, + locations_data: `${BASE_URL}/locations`, + locations_history: `${BASE_URL}/locations/history`, + projects: `${BASE_URL}/projects` + }, + }) }) -/* - -TODO - -Deezer Songs: - -Tasks: kernel : setTimeout or cron - Deezer songs: 1min - */ - Route.get('/source', async ({response}: HttpContextContract) => { return response.redirect('https://github.com/arthurdanjou/artapi') }) -Route.get('/location', 'LocationsController.get') -Route.get('/location/history', 'LocationsController.history') + +Route.get('health', async ({response}: HttpContextContract) => { + const report = await HealthCheck.getReport() + return report.healthy ? response.ok(report) : response.badRequest(report) +}) + +Route.get('/me', 'MeController.me') +Route.get('/locations', 'LocationsController.get') +Route.get('/locations/history', 'LocationsController.history') Route.get('/stats', 'StatsController.get') -Route.get('/state', 'StatesController.get') +Route.get('/states', 'StatesController.get') +Route.get('/projects', 'ProjectsController.get') Route.resource('users', 'UsersController').only(['index', 'show']) Route.get('/posts/:slug', 'PostsController.getLikes') Route.get('/posts/is/:slug', 'PostsController.isLiked') Route.post('/posts/:slug/like', 'PostsController.like') Route.post('/posts/:slug/unlike', 'PostsController.unlike') Route.resource('subscribers', 'SubscribersController').only(['index', 'show']) -Route.resource('files', 'FileController').only(['index']) -Route.get('/files/:filename', async ({ response, params }) => { - response.download(Application.makePath('storage', params.filename)) -}) +Route.group(() => { + Route.get('/', 'FileController.index') + Route.get('/:filename', async ({ response, params }) => { + response.download(Application.makePath('storage', params.filename)) + }) +}).prefix('/files') Route.group(() => { Route.resource('users', 'UsersController').only(['store', 'update', 'destroy']) Route.resource('posts', 'PostsController').only(['store', 'update', 'destroy']) Route.resource('subscribers', 'SubscribersController').only(['store', 'update', 'destroy']) Route.resource('files', 'FileController').only(['store', 'destroy']) - Route.post('/state', 'StatesController.set') + Route.post('/states', 'StatesController.set') Route.post('/stats/build', 'StatesController.incrementBuild') Route.post('/stats/command', 'StatesController.incrementCommand') - Route.post('/location', 'StatesController.set') - + Route.post('/locations', 'StatesController.add') + Route.post('/projects', 'ProjectsController.add') }).middleware('auth') Route.group(() => {