mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 14:43:24 +00:00
refactor: collection controllers and service
This commit is contained in:
@@ -31,14 +31,14 @@ type AuthLogoutGetHead = {
|
|||||||
type DashboardGetHead = {
|
type DashboardGetHead = {
|
||||||
request: unknown;
|
request: unknown;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['index'],
|
import('../app/collections/controllers/show_collections_controller.ts').default['render'],
|
||||||
false
|
false
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
type CollectionsCreateGetHead = {
|
type CollectionsCreateGetHead = {
|
||||||
request: unknown;
|
request: unknown;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['showCreatePage'],
|
import('../app/collections/controllers/create_collection_controller.ts').default['render'],
|
||||||
false
|
false
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
@@ -49,14 +49,14 @@ type CollectionsPost = {
|
|||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['store'],
|
import('../app/collections/controllers/create_collection_controller.ts').default['execute'],
|
||||||
true
|
true
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
type CollectionsEditGetHead = {
|
type CollectionsEditGetHead = {
|
||||||
request: unknown;
|
request: unknown;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['showEditPage'],
|
import('../app/collections/controllers/update_collection_controller.ts').default['render'],
|
||||||
false
|
false
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
@@ -67,14 +67,14 @@ type CollectionsIdPut = {
|
|||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['update'],
|
import('../app/collections/controllers/update_collection_controller.ts').default['execute'],
|
||||||
true
|
true
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
type CollectionsDeleteGetHead = {
|
type CollectionsDeleteGetHead = {
|
||||||
request: unknown;
|
request: unknown;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['showDeletePage'],
|
import('../app/collections/controllers/delete_collection_controller.ts').default['render'],
|
||||||
false
|
false
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
@@ -85,7 +85,7 @@ type CollectionsIdDelete = {
|
|||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
response: MakeTuyauResponse<
|
response: MakeTuyauResponse<
|
||||||
import('../app/collections/controllers/collections_controller.ts').default['delete'],
|
import('../app/collections/controllers/delete_collection_controller.ts').default['execute'],
|
||||||
true
|
true
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ NODE_ENV=development
|
|||||||
SESSION_DRIVER=cookie
|
SESSION_DRIVER=cookie
|
||||||
DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_USER=postgres
|
DB_USER=root
|
||||||
DB_PASSWORD=my-links-pwd
|
DB_PASSWORD=root
|
||||||
DB_DATABASE=my-links
|
DB_DATABASE=app
|
||||||
GOOGLE_CLIENT_ID=
|
GOOGLE_CLIENT_ID=
|
||||||
GOOGLE_CLIENT_SECRET=
|
GOOGLE_CLIENT_SECRET=
|
||||||
GOOGLE_CLIENT_CALLBACK_URL=http://localhost:3333/auth/callback
|
GOOGLE_CLIENT_CALLBACK_URL=http://localhost:3333/auth/callback
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import AuthController from '#auth/controllers/auth_controller';
|
import AuthController from '#auth/controllers/auth_controller';
|
||||||
import CollectionsController from '#collections/controllers/collections_controller';
|
import CollectionsController from '#collections/controllers/show_collections_controller';
|
||||||
import LinksController from '#links/controllers/links_controller';
|
import LinksController from '#links/controllers/links_controller';
|
||||||
import User from '#user/models/user';
|
import User from '#user/models/user';
|
||||||
import { inject } from '@adonisjs/core';
|
import { inject } from '@adonisjs/core';
|
||||||
|
|||||||
32
app/collections/controllers/base_collection_controller.ts
Normal file
32
app/collections/controllers/base_collection_controller.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import Collection from '#collections/models/collection';
|
||||||
|
import { HttpContext } from '@adonisjs/core/http';
|
||||||
|
import vine from '@vinejs/vine';
|
||||||
|
|
||||||
|
export default class BaseCollectionController {
|
||||||
|
protected collectionIdValidator = vine.compile(
|
||||||
|
vine.object({
|
||||||
|
collectionId: vine.number().positive().optional(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
async validateCollectionId(collectionIdRequired: boolean = true) {
|
||||||
|
const ctx = HttpContext.getOrFail();
|
||||||
|
const { collectionId } = await ctx.request.validateUsing(
|
||||||
|
this.collectionIdValidator
|
||||||
|
);
|
||||||
|
if (!collectionId && collectionIdRequired) {
|
||||||
|
console.log('redirecting to dashboard');
|
||||||
|
ctx.response.redirectToNamedRoute('dashboard');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
console.log('collectionId', collectionId);
|
||||||
|
return collectionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectToCollectionId(collectionId: Collection['id']) {
|
||||||
|
const ctx = HttpContext.getOrFail();
|
||||||
|
return ctx.response.redirectToNamedRoute('dashboard', {
|
||||||
|
qs: { collectionId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
import Collection from '#collections/models/collection';
|
|
||||||
import { createCollectionValidator } from '#collections/validators/create_collection_validator';
|
|
||||||
import { deleteCollectionValidator } from '#collections/validators/delete_collection_validator';
|
|
||||||
import { updateCollectionValidator } from '#collections/validators/update_collection_validator';
|
|
||||||
import User from '#user/models/user';
|
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
|
||||||
import db from '@adonisjs/lucid/services/db';
|
|
||||||
|
|
||||||
export default class CollectionsController {
|
|
||||||
// Dashboard
|
|
||||||
async index({ auth, inertia, request, response }: HttpContext) {
|
|
||||||
const collections = await this.getCollectionsByAuthorId(auth.user!.id);
|
|
||||||
if (collections.length === 0) {
|
|
||||||
return response.redirectToNamedRoute('collection.create-form');
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeCollectionId = Number(request.qs()?.collectionId ?? '');
|
|
||||||
const activeCollection = collections.find(
|
|
||||||
(c) => c.id === activeCollectionId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!activeCollection && !!activeCollectionId) {
|
|
||||||
return response.redirectToNamedRoute('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Create DTOs
|
|
||||||
return inertia.render('dashboard', {
|
|
||||||
collections: collections.map((collection) => collection.serialize()),
|
|
||||||
activeCollection:
|
|
||||||
activeCollection?.serialize() || collections[0].serialize(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create collection form
|
|
||||||
async showCreatePage({ inertia, auth }: HttpContext) {
|
|
||||||
const collections = await this.getCollectionsByAuthorId(auth.user!.id);
|
|
||||||
return inertia.render('collections/create', {
|
|
||||||
disableHomeLink: collections.length === 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method called when creating a collection
|
|
||||||
async store({ request, response, auth }: HttpContext) {
|
|
||||||
const payload = await request.validateUsing(createCollectionValidator);
|
|
||||||
const collection = await Collection.create({
|
|
||||||
...payload,
|
|
||||||
authorId: auth.user?.id!,
|
|
||||||
});
|
|
||||||
return this.redirectToCollectionId(response, collection.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async showEditPage({ auth, request, inertia, response }: HttpContext) {
|
|
||||||
const collectionId = request.qs()?.collectionId;
|
|
||||||
if (!collectionId) {
|
|
||||||
return response.redirectToNamedRoute('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
const collection = await this.getCollectionById(
|
|
||||||
collectionId,
|
|
||||||
auth.user!.id
|
|
||||||
);
|
|
||||||
return inertia.render('collections/edit', {
|
|
||||||
collection,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async update({ request, auth, response }: HttpContext) {
|
|
||||||
const { params, ...payload } = await request.validateUsing(
|
|
||||||
updateCollectionValidator
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cant use validator (vinejs) custom rule 'cause its too generic,
|
|
||||||
// because we have to find a collection by identifier and
|
|
||||||
// check whether the current user is the author.
|
|
||||||
// https://vinejs.dev/docs/extend/custom_rules
|
|
||||||
await this.getCollectionById(params.id, auth.user!.id);
|
|
||||||
|
|
||||||
await Collection.updateOrCreate(
|
|
||||||
{
|
|
||||||
id: params.id,
|
|
||||||
},
|
|
||||||
payload
|
|
||||||
);
|
|
||||||
return this.redirectToCollectionId(response, params.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async showDeletePage({ auth, request, inertia, response }: HttpContext) {
|
|
||||||
const collectionId = request.qs()?.collectionId;
|
|
||||||
if (!collectionId) {
|
|
||||||
return response.redirectToNamedRoute('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
const collection = await this.getCollectionById(
|
|
||||||
collectionId,
|
|
||||||
auth.user!.id
|
|
||||||
);
|
|
||||||
return inertia.render('collections/delete', {
|
|
||||||
collection,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async delete({ request, auth, response }: HttpContext) {
|
|
||||||
const { params } = await request.validateUsing(deleteCollectionValidator);
|
|
||||||
const collection = await this.getCollectionById(params.id, auth.user!.id);
|
|
||||||
await collection.delete();
|
|
||||||
return response.redirectToNamedRoute('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTotalCollectionsCount() {
|
|
||||||
const totalCount = await db.from('collections').count('* as total');
|
|
||||||
return Number(totalCount[0].total);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get collection by id.
|
|
||||||
*
|
|
||||||
* /!\ Only return private collection (create by the current user)
|
|
||||||
*/
|
|
||||||
async getCollectionById(id: Collection['id'], userId: User['id']) {
|
|
||||||
return await Collection.query()
|
|
||||||
.where('id', id)
|
|
||||||
.andWhere('author_id', userId)
|
|
||||||
.firstOrFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCollectionsByAuthorId(authorId: User['id']) {
|
|
||||||
return await Collection.query()
|
|
||||||
.where('author_id', authorId)
|
|
||||||
.orderBy('created_at')
|
|
||||||
.preload('links');
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectToCollectionId(
|
|
||||||
response: HttpContext['response'],
|
|
||||||
collectionId: Collection['id']
|
|
||||||
) {
|
|
||||||
return response.redirectToNamedRoute('dashboard', {
|
|
||||||
qs: { collectionId },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
app/collections/controllers/create_collection_controller.ts
Normal file
25
app/collections/controllers/create_collection_controller.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import BaseCollectionController from '#collections/controllers/base_collection_controller';
|
||||||
|
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 extends BaseCollectionController {
|
||||||
|
constructor(private collectionService: CollectionService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async render({ inertia }: HttpContext) {
|
||||||
|
const collections = await this.collectionService.getCollectionsByAuthorId();
|
||||||
|
return inertia.render('collections/create', {
|
||||||
|
disableHomeLink: collections.length === 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute({ request }: HttpContext) {
|
||||||
|
const payload = await request.validateUsing(createCollectionValidator);
|
||||||
|
const collection = await this.collectionService.createCollection(payload);
|
||||||
|
return this.redirectToCollectionId(collection.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/collections/controllers/delete_collection_controller.ts
Normal file
29
app/collections/controllers/delete_collection_controller.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import BaseCollectionController from '#collections/controllers/base_collection_controller';
|
||||||
|
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 extends BaseCollectionController {
|
||||||
|
constructor(private collectionService: CollectionService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async render({ inertia }: HttpContext) {
|
||||||
|
const collectionId = await this.validateCollectionId();
|
||||||
|
if (!collectionId) return;
|
||||||
|
|
||||||
|
const collection =
|
||||||
|
await this.collectionService.getCollectionById(collectionId);
|
||||||
|
return inertia.render('collections/delete', {
|
||||||
|
collection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute({ request, response }: HttpContext) {
|
||||||
|
const { params } = await request.validateUsing(deleteCollectionValidator);
|
||||||
|
await this.collectionService.deleteCollection(params.id);
|
||||||
|
return response.redirectToNamedRoute('dashboard');
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/collections/controllers/show_collections_controller.ts
Normal file
34
app/collections/controllers/show_collections_controller.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import BaseCollectionController from '#collections/controllers/base_collection_controller';
|
||||||
|
import { CollectionService } from '#collections/services/collection_service';
|
||||||
|
import { inject } from '@adonisjs/core';
|
||||||
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
|
|
||||||
|
@inject()
|
||||||
|
export default class ShowCollectionsController extends BaseCollectionController {
|
||||||
|
constructor(private collectionService: CollectionService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dashboard
|
||||||
|
async render({ inertia, response }: HttpContext) {
|
||||||
|
const activeCollectionId = await this.validateCollectionId(false);
|
||||||
|
const collections = await this.collectionService.getCollectionsByAuthorId();
|
||||||
|
if (collections.length === 0) {
|
||||||
|
return response.redirectToNamedRoute('collection.create-form');
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeCollection = collections.find(
|
||||||
|
(c) => c.id === activeCollectionId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!activeCollection && !!activeCollectionId) {
|
||||||
|
return response.redirectToNamedRoute('dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
return inertia.render('dashboard', {
|
||||||
|
collections: collections.map((collection) => collection.serialize()),
|
||||||
|
activeCollection:
|
||||||
|
activeCollection?.serialize() || collections[0].serialize(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
33
app/collections/controllers/update_collection_controller.ts
Normal file
33
app/collections/controllers/update_collection_controller.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import BaseCollectionController from '#collections/controllers/base_collection_controller';
|
||||||
|
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 extends BaseCollectionController {
|
||||||
|
constructor(private collectionService: CollectionService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async render({ inertia }: HttpContext) {
|
||||||
|
const collectionId = await this.validateCollectionId();
|
||||||
|
if (!collectionId) return;
|
||||||
|
|
||||||
|
const collection =
|
||||||
|
await this.collectionService.getCollectionById(collectionId);
|
||||||
|
return inertia.render('collections/update', {
|
||||||
|
collection: collection.serialize(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute({ request }: HttpContext) {
|
||||||
|
const {
|
||||||
|
params: { id: collectionId },
|
||||||
|
...payload
|
||||||
|
} = await request.validateUsing(updateCollectionValidator);
|
||||||
|
|
||||||
|
await this.collectionService.updateCollection(collectionId, payload);
|
||||||
|
return this.redirectToCollectionId(collectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,45 @@
|
|||||||
import { middleware } from '#start/kernel';
|
import { middleware } from '#start/kernel';
|
||||||
import router from '@adonisjs/core/services/router';
|
import router from '@adonisjs/core/services/router';
|
||||||
const CollectionsController = () =>
|
|
||||||
import('#collections/controllers/collections_controller');
|
const ShowCollectionsController = () =>
|
||||||
|
import('#collections/controllers/show_collections_controller');
|
||||||
|
const CreateCollectionController = () =>
|
||||||
|
import('#collections/controllers/create_collection_controller');
|
||||||
|
const UpdateCollectionController = () =>
|
||||||
|
import('#collections/controllers/update_collection_controller');
|
||||||
|
const DeleteCollectionController = () =>
|
||||||
|
import('#collections/controllers/delete_collection_controller');
|
||||||
|
|
||||||
router
|
router
|
||||||
.group(() => {
|
.group(() => {
|
||||||
router.get('/dashboard', [CollectionsController, 'index']).as('dashboard');
|
router
|
||||||
|
.get('/dashboard', [ShowCollectionsController, 'render'])
|
||||||
|
.as('dashboard');
|
||||||
|
|
||||||
router
|
router
|
||||||
.group(() => {
|
.group(() => {
|
||||||
|
// Create
|
||||||
router
|
router
|
||||||
.get('/create', [CollectionsController, 'showCreatePage'])
|
.get('/create', [CreateCollectionController, 'render'])
|
||||||
.as('collection.create-form');
|
.as('collection.create-form');
|
||||||
router
|
router
|
||||||
.post('/', [CollectionsController, 'store'])
|
.post('/', [CreateCollectionController, 'execute'])
|
||||||
.as('collection.create');
|
.as('collection.create');
|
||||||
|
|
||||||
|
// Update
|
||||||
router
|
router
|
||||||
.get('/edit', [CollectionsController, 'showEditPage'])
|
.get('/edit', [UpdateCollectionController, 'render'])
|
||||||
.as('collection.edit-form');
|
.as('collection.edit-form');
|
||||||
router
|
router
|
||||||
.put('/:id', [CollectionsController, 'update'])
|
.put('/:id', [UpdateCollectionController, 'execute'])
|
||||||
.as('collection.edit');
|
.as('collection.edit');
|
||||||
|
|
||||||
|
// Delete
|
||||||
router
|
router
|
||||||
.get('/delete', [CollectionsController, 'showDeletePage'])
|
.get('/delete', [DeleteCollectionController, 'render'])
|
||||||
.as('collection.delete-form');
|
.as('collection.delete-form');
|
||||||
router
|
router
|
||||||
.delete('/:id', [CollectionsController, 'delete'])
|
.delete('/:id', [DeleteCollectionController, 'execute'])
|
||||||
.as('collection.delete');
|
.as('collection.delete');
|
||||||
})
|
})
|
||||||
.prefix('/collections');
|
.prefix('/collections');
|
||||||
|
|||||||
70
app/collections/services/collection_service.ts
Normal file
70
app/collections/services/collection_service.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { Visibility } from '#collections/enums/visibility';
|
||||||
|
import Collection from '#collections/models/collection';
|
||||||
|
import { HttpContext } from '@adonisjs/core/http';
|
||||||
|
import db from '@adonisjs/lucid/services/db';
|
||||||
|
|
||||||
|
type CreateCollectionPayload = {
|
||||||
|
name: string;
|
||||||
|
description: string | null;
|
||||||
|
visibility: Visibility;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UpdateCollectionPayload = CreateCollectionPayload;
|
||||||
|
|
||||||
|
export class CollectionService {
|
||||||
|
async getCollectionById(id: Collection['id']) {
|
||||||
|
const context = this.getAuthContext();
|
||||||
|
return await Collection.query()
|
||||||
|
.where('id', id)
|
||||||
|
.andWhere('author_id', context.auth.user!.id)
|
||||||
|
.firstOrFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCollectionsByAuthorId() {
|
||||||
|
const context = this.getAuthContext();
|
||||||
|
return await Collection.query()
|
||||||
|
.where('author_id', context.auth.user!.id)
|
||||||
|
.orderBy('created_at')
|
||||||
|
.preload('links');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTotalCollectionsCount() {
|
||||||
|
const totalCount = await db.from('collections').count('* as total');
|
||||||
|
return Number(totalCount[0].total);
|
||||||
|
}
|
||||||
|
|
||||||
|
createCollection(payload: CreateCollectionPayload) {
|
||||||
|
const context = this.getAuthContext();
|
||||||
|
return Collection.create({
|
||||||
|
...payload,
|
||||||
|
authorId: context.auth.user!.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateCollection(
|
||||||
|
id: Collection['id'],
|
||||||
|
payload: UpdateCollectionPayload
|
||||||
|
) {
|
||||||
|
const context = this.getAuthContext();
|
||||||
|
return await Collection.query()
|
||||||
|
.where('id', id)
|
||||||
|
.andWhere('author_id', context.auth.user!.id)
|
||||||
|
.update(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCollection(id: Collection['id']) {
|
||||||
|
const context = this.getAuthContext();
|
||||||
|
return Collection.query()
|
||||||
|
.where('id', id)
|
||||||
|
.andWhere('author_id', context.auth.user!.id)
|
||||||
|
.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuthContext() {
|
||||||
|
const context = HttpContext.getOrFail();
|
||||||
|
if (!context.auth.user || !context.auth.user.id) {
|
||||||
|
throw new Error('User not authenticated');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import CollectionsController from '#collections/controllers/collections_controller';
|
import CollectionsController from '#collections/controllers/show_collections_controller';
|
||||||
import Link from '#links/models/link';
|
import Link from '#links/models/link';
|
||||||
import { createLinkValidator } from '#links/validators/create_link_validator';
|
import { createLinkValidator } from '#links/validators/create_link_validator';
|
||||||
import { deleteLinkValidator } from '#links/validators/delete_link_validator';
|
import { deleteLinkValidator } from '#links/validators/delete_link_validator';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import env from '#start/env';
|
import env from '#start/env';
|
||||||
import app from '@adonisjs/core/services/app';
|
|
||||||
import { Secret } from '@adonisjs/core/helpers';
|
import { Secret } from '@adonisjs/core/helpers';
|
||||||
import { defineConfig } from '@adonisjs/core/http';
|
import { defineConfig } from '@adonisjs/core/http';
|
||||||
|
import app from '@adonisjs/core/services/app';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The app key is used for encrypting cookies, generating signed URLs,
|
* The app key is used for encrypting cookies, generating signed URLs,
|
||||||
@@ -23,7 +23,7 @@ export const http = defineConfig({
|
|||||||
* Enabling async local storage will let you access HTTP context
|
* Enabling async local storage will let you access HTTP context
|
||||||
* from anywhere inside your application.
|
* from anywhere inside your application.
|
||||||
*/
|
*/
|
||||||
useAsyncLocalStorage: false,
|
useAsyncLocalStorage: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage cookies configuration. The settings for the session id cookie are
|
* Manage cookies configuration. The settings for the session id cookie are
|
||||||
|
|||||||
48
inertia/hooks/use_route.tsx
Normal file
48
inertia/hooks/use_route.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { ApiRouteName } from '#shared/types/index';
|
||||||
|
import { useTuyau } from '@tuyau/inertia/react';
|
||||||
|
import { buildUrl } from '~/lib/navigation';
|
||||||
|
|
||||||
|
interface TuyauRoute {
|
||||||
|
route: ApiRouteName;
|
||||||
|
params?: Record<string, string>; // TODO: add type
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NonTuyauRoute {
|
||||||
|
href: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type UseRouteProps = TuyauRoute | NonTuyauRoute;
|
||||||
|
|
||||||
|
type TuyauReturn = {
|
||||||
|
url: string;
|
||||||
|
method: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NonTuyauReturn = {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseRouteReturn<T extends UseRouteProps> = T extends TuyauRoute
|
||||||
|
? TuyauReturn
|
||||||
|
: NonTuyauReturn;
|
||||||
|
|
||||||
|
export const useRoute = <T extends UseRouteProps>(
|
||||||
|
props: T
|
||||||
|
): UseRouteReturn<T> => {
|
||||||
|
const tuyau = useTuyau();
|
||||||
|
if ('href' in props) {
|
||||||
|
return {
|
||||||
|
url: props.href,
|
||||||
|
} as UseRouteReturn<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const route = tuyau?.$route(props.route, props.params);
|
||||||
|
if (!route) {
|
||||||
|
throw new Error(`Route ${props.route} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: buildUrl(route.path, props.params ?? {}),
|
||||||
|
method: route.method,
|
||||||
|
} as UseRouteReturn<T>;
|
||||||
|
};
|
||||||
@@ -34,3 +34,11 @@ export const generateShareUrl = (
|
|||||||
if (typeof window === 'undefined') return pathname;
|
if (typeof window === 'undefined') return pathname;
|
||||||
return `${window.location.origin}${pathname}`;
|
return `${window.location.origin}${pathname}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildUrl = (url: string, params: Record<string, string>) => {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
urlObj.searchParams.set(key, value);
|
||||||
|
});
|
||||||
|
return urlObj.toString();
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user