mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 14:43:24 +00:00
feat: add api controllers and routes for browser extension
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { CollectionService } from '#collections/services/collection_service';
|
||||
import { createCollectionValidator } from '#collections/validators/create_collection_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { type HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class CreateCollectionController {
|
||||
constructor(private collectionService: CollectionService) {}
|
||||
|
||||
async execute({ request, response }: HttpContext) {
|
||||
console.log('avant');
|
||||
const payload = await request.validateUsing(createCollectionValidator);
|
||||
const collection = await this.collectionService.createCollection(payload);
|
||||
console.log('après', collection);
|
||||
return response.json({
|
||||
message: 'Collection created successfully',
|
||||
collection: collection.serialize(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { CollectionService } from '#collections/services/collection_service';
|
||||
import { deleteCollectionValidator } from '#collections/validators/delete_collection_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class DeleteCollectionController {
|
||||
constructor(private collectionService: CollectionService) {}
|
||||
|
||||
async execute({ request, response }: HttpContext) {
|
||||
const { params } = await request.validateUsing(deleteCollectionValidator);
|
||||
await this.collectionService.deleteCollection(params.id);
|
||||
return response.json({
|
||||
message: 'Collection deleted successfully',
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CollectionService } from '#collections/services/collection_service';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class GetCollectionsController {
|
||||
constructor(private collectionService: CollectionService) {}
|
||||
|
||||
async show({ response }: HttpContext) {
|
||||
const collections =
|
||||
await this.collectionService.getCollectionsForAuthenticatedUser();
|
||||
return response.json({
|
||||
collections: collections.map((collection) => collection.serialize()),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { CollectionService } from '#collections/services/collection_service';
|
||||
import { updateCollectionValidator } from '#collections/validators/update_collection_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class UpdateCollectionController {
|
||||
constructor(private collectionService: CollectionService) {}
|
||||
|
||||
async execute({ request, response }: HttpContext) {
|
||||
const {
|
||||
params: { id: collectionId },
|
||||
...payload
|
||||
} = await request.validateUsing(updateCollectionValidator);
|
||||
|
||||
await this.collectionService.updateCollection(collectionId, payload);
|
||||
return response.json({
|
||||
message: 'Collection updated successfully',
|
||||
});
|
||||
}
|
||||
}
|
||||
14
app/api/collections/routes/api_create_collections_routes.ts
Normal file
14
app/api/collections/routes/api_create_collections_routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const CreateCollectionsController = () =>
|
||||
import('#api/collections/controllers/create_collection_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.post('', [CreateCollectionsController, 'execute'])
|
||||
.as('api-collections.create');
|
||||
})
|
||||
.prefix('/api/v1/collections')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/collections/routes/api_delete_collections_routes.ts
Normal file
14
app/api/collections/routes/api_delete_collections_routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const DeleteCollectionsController = () =>
|
||||
import('#api/collections/controllers/delete_collection_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.delete('/:id', [DeleteCollectionsController, 'execute'])
|
||||
.as('api-collections.delete');
|
||||
})
|
||||
.prefix('/api/v1/collections')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/collections/routes/api_get_collections_routes.ts
Normal file
14
app/api/collections/routes/api_get_collections_routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const GetCollectionsController = () =>
|
||||
import('#api/collections/controllers/get_collections_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('', [GetCollectionsController, 'show'])
|
||||
.as('api-collections.index');
|
||||
})
|
||||
.prefix('/api/v1/collections')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/collections/routes/api_update_collections_routes.ts
Normal file
14
app/api/collections/routes/api_update_collections_routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const UpdateCollectionsController = () =>
|
||||
import('#api/collections/controllers/update_collection_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.put('/:id', [UpdateCollectionsController, 'execute'])
|
||||
.as('api-collections.update');
|
||||
})
|
||||
.prefix('/api/v1/collections')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
4
app/api/collections/routes/routes.ts
Normal file
4
app/api/collections/routes/routes.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import '#api/collections/routes/api_create_collections_routes';
|
||||
import '#api/collections/routes/api_delete_collections_routes';
|
||||
import '#api/collections/routes/api_get_collections_routes';
|
||||
import '#api/collections/routes/api_update_collections_routes';
|
||||
23
app/api/links/controllers/create_link_controller.ts
Normal file
23
app/api/links/controllers/create_link_controller.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { LinkService } from '#links/services/link_service';
|
||||
import { createLinkValidator } from '#links/validators/create_link_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class CreateLinkController {
|
||||
constructor(private linkService: LinkService) {}
|
||||
|
||||
async execute({ request, response }: HttpContext) {
|
||||
const { collectionId, ...payload } =
|
||||
await request.validateUsing(createLinkValidator);
|
||||
|
||||
const link = await this.linkService.createLink({
|
||||
...payload,
|
||||
collectionId,
|
||||
});
|
||||
return response.json({
|
||||
message: 'Link created successfully',
|
||||
link: link.serialize(),
|
||||
});
|
||||
}
|
||||
}
|
||||
39
app/api/links/controllers/delete_link_controller.ts
Normal file
39
app/api/links/controllers/delete_link_controller.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CollectionService } from '#collections/services/collection_service';
|
||||
import { LinkService } from '#links/services/link_service';
|
||||
import { deleteLinkValidator } from '#links/validators/delete_link_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
import db from '@adonisjs/lucid/services/db';
|
||||
|
||||
@inject()
|
||||
export default class DeleteLinkController {
|
||||
constructor(
|
||||
protected collectionsService: CollectionService,
|
||||
protected linkService: LinkService
|
||||
) {}
|
||||
|
||||
async render({ auth, inertia, request }: HttpContext) {
|
||||
const linkId = request.qs()?.linkId;
|
||||
if (!linkId) {
|
||||
return this.collectionsService.redirectToDashboard();
|
||||
}
|
||||
|
||||
const link = await this.linkService.getLinkById(linkId, auth.user!.id);
|
||||
await link.load('collection');
|
||||
return inertia.render('links/delete', { link });
|
||||
}
|
||||
|
||||
async execute({ request, auth }: HttpContext) {
|
||||
const { params } = await request.validateUsing(deleteLinkValidator);
|
||||
|
||||
const link = await this.linkService.getLinkById(params.id, auth.user!.id);
|
||||
await this.linkService.deleteLink(params.id);
|
||||
|
||||
return this.collectionsService.redirectToCollectionId(link.collectionId);
|
||||
}
|
||||
|
||||
async getTotalLinksCount() {
|
||||
const totalCount = await db.from('links').count('* as total');
|
||||
return Number(totalCount[0].total);
|
||||
}
|
||||
}
|
||||
13
app/api/links/controllers/get_favorite_links_controller.ts
Normal file
13
app/api/links/controllers/get_favorite_links_controller.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { LinkService } from '#links/services/link_service';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class GetFavoriteLinksController {
|
||||
constructor(private linkService: LinkService) {}
|
||||
|
||||
public async execute({ response }: HttpContext) {
|
||||
const links = await this.linkService.getFavoriteLinksForAuthenticatedUser();
|
||||
return response.json(links);
|
||||
}
|
||||
}
|
||||
19
app/api/links/controllers/update_link_controller.ts
Normal file
19
app/api/links/controllers/update_link_controller.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { LinkService } from '#links/services/link_service';
|
||||
import { updateLinkValidator } from '#links/validators/update_link_validator';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class UpdateLinkController {
|
||||
constructor(private linkService: LinkService) {}
|
||||
|
||||
async execute({ request, response }: HttpContext) {
|
||||
const { params, ...payload } =
|
||||
await request.validateUsing(updateLinkValidator);
|
||||
|
||||
await this.linkService.updateLink(params.id, payload);
|
||||
return response.json({
|
||||
message: 'Link updated successfully',
|
||||
});
|
||||
}
|
||||
}
|
||||
12
app/api/links/routes/api_create_link_routes.ts
Normal file
12
app/api/links/routes/api_create_link_routes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const CreateLinkController = () =>
|
||||
import('#api/links/controllers/create_link_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router.post('', [CreateLinkController, 'execute']).as('api-links.create');
|
||||
})
|
||||
.prefix('/api/v1/links')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/links/routes/api_delete_link_route.ts
Normal file
14
app/api/links/routes/api_delete_link_route.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const DeleteLinkController = () =>
|
||||
import('#api/links/controllers/delete_link_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.delete('/:id', [DeleteLinkController, 'execute'])
|
||||
.as('api-links.delete');
|
||||
})
|
||||
.prefix('/api/v1/links')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/links/routes/api_get_favorite_links_routes.ts
Normal file
14
app/api/links/routes/api_get_favorite_links_routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const GetFavoriteLinksController = () =>
|
||||
import('#api/links/controllers/get_favorite_links_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.get('', [GetFavoriteLinksController, 'execute'])
|
||||
.as('api-links.get-favorite-links');
|
||||
})
|
||||
.prefix('/api/v1/links/favorites')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
14
app/api/links/routes/api_update_link_route.ts
Normal file
14
app/api/links/routes/api_update_link_route.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const UpdateLinkController = () =>
|
||||
import('#api/links/controllers/update_link_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router
|
||||
.put('/:id', [UpdateLinkController, 'execute'])
|
||||
.as('api-links.update');
|
||||
})
|
||||
.prefix('/api/v1/links')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
4
app/api/links/routes/routes.ts
Normal file
4
app/api/links/routes/routes.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import '#api/links/routes/api_create_link_routes';
|
||||
import '#api/links/routes/api_delete_link_route';
|
||||
import '#api/links/routes/api_get_favorite_links_routes';
|
||||
import '#api/links/routes/api_update_link_route';
|
||||
18
app/api/tokens/controllers/api_token_controller.ts
Normal file
18
app/api/tokens/controllers/api_token_controller.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import UnAuthorizedException from '#api/tokens/exceptions/un_authorized_exception';
|
||||
import { getTokenFromHeader } from '#api/tokens/lib/index';
|
||||
import { inject } from '@adonisjs/core';
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
@inject()
|
||||
export default class ApiTokenController {
|
||||
async index(ctx: HttpContext) {
|
||||
const token = getTokenFromHeader(ctx);
|
||||
if (!token) {
|
||||
throw new UnAuthorizedException();
|
||||
}
|
||||
|
||||
return ctx.response.json({
|
||||
message: 'Token is valid',
|
||||
});
|
||||
}
|
||||
}
|
||||
7
app/api/tokens/exceptions/un_authorized_exception.ts
Normal file
7
app/api/tokens/exceptions/un_authorized_exception.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Exception } from '@adonisjs/core/exceptions';
|
||||
|
||||
export default class UnAuthorizedException extends Exception {
|
||||
static status = 401;
|
||||
message = 'Missing or invalid authorization header';
|
||||
code = 'UNAUTHORIZED';
|
||||
}
|
||||
11
app/api/tokens/lib/index.ts
Normal file
11
app/api/tokens/lib/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { HttpContext } from '@adonisjs/core/http';
|
||||
|
||||
export function getTokenFromHeader(ctx: HttpContext) {
|
||||
const authHeader = ctx.request.header('Authorization');
|
||||
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return authHeader.substring(7);
|
||||
}
|
||||
12
app/api/tokens/routes/api_token_routes.ts
Normal file
12
app/api/tokens/routes/api_token_routes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { middleware } from '#start/kernel';
|
||||
import router from '@adonisjs/core/services/router';
|
||||
|
||||
const ApiTokenController = () =>
|
||||
import('#api/tokens/controllers/api_token_controller');
|
||||
|
||||
router
|
||||
.group(() => {
|
||||
router.get('/check', [ApiTokenController, 'index']).as('api-tokens.index');
|
||||
})
|
||||
.prefix('/api/v1/tokens')
|
||||
.middleware([middleware.auth({ guards: ['api'] })]);
|
||||
1
app/api/tokens/routes/routes.ts
Normal file
1
app/api/tokens/routes/routes.ts
Normal file
@@ -0,0 +1 @@
|
||||
import '#api/tokens/routes/api_token_routes';
|
||||
@@ -36,6 +36,13 @@ export default class HttpExceptionHandler extends ExceptionHandler {
|
||||
* response to the client
|
||||
*/
|
||||
async handle(error: unknown, ctx: HttpContext) {
|
||||
if (ctx.request.url()?.startsWith('/api/v1')) {
|
||||
return ctx.response.status(400).json({
|
||||
message: 'Bad Request',
|
||||
errors: [error],
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof errors.E_ROW_NOT_FOUND) {
|
||||
return ctx.response.redirectToNamedRoute('dashboard');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import User from '#user/models/user';
|
||||
import { AccessToken } from '@adonisjs/auth/access_tokens';
|
||||
|
||||
type CreateTokenParams = {
|
||||
name: string;
|
||||
@@ -23,10 +22,6 @@ export class ApiTokenService {
|
||||
return User.accessTokens.delete(user, identifier);
|
||||
}
|
||||
|
||||
validateToken(token: AccessToken) {
|
||||
return User.accessTokens.verify(token.value!);
|
||||
}
|
||||
|
||||
getTokenByValue(user: User, value: string) {
|
||||
return User.accessTokens.find(user, value);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { defineConfig } from '@adonisjs/auth';
|
||||
import { tokensGuard, tokensUserProvider } from '@adonisjs/auth/access_tokens';
|
||||
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session';
|
||||
import { Authenticators, InferAuthEvents } from '@adonisjs/auth/types';
|
||||
|
||||
@@ -11,6 +12,12 @@ const authConfig = defineConfig({
|
||||
model: () => import('#user/models/user'),
|
||||
}),
|
||||
}),
|
||||
api: tokensGuard({
|
||||
provider: tokensUserProvider({
|
||||
tokens: 'accessTokens',
|
||||
model: () => import('#user/models/user'),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"#admin/*": "./app/admin/*.js",
|
||||
"#adonis/api": "./.adonisjs/api.ts",
|
||||
"#auth/*": "./app/auth/*.js",
|
||||
"#api/*": "./app/api/*.js",
|
||||
"#collections/*": "./app/collections/*.js",
|
||||
"#config/*": "./config/*.js",
|
||||
"#core/*": "./app/core/*.js",
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import '#admin/routes/routes';
|
||||
import '#api/collections/routes/routes';
|
||||
import '#api/links/routes/routes';
|
||||
import '#api/tokens/routes/routes';
|
||||
import '#auth/routes/routes';
|
||||
import '#collections/routes/routes';
|
||||
import '#favicons/routes/routes';
|
||||
|
||||
Reference in New Issue
Block a user