diff --git a/.adonisjs/client/data.d.ts b/.adonisjs/client/data.d.ts index dc95553..fbfcce0 100644 --- a/.adonisjs/client/data.d.ts +++ b/.adonisjs/client/data.d.ts @@ -6,28 +6,32 @@ /// import type { InferData, InferVariants } from '@adonisjs/core/types/transformers' import type { InferSharedProps, InferFlashData } from '@adonisjs/inertia/types' -import type BuildLogTransformer from '#transformers/build_log_transformer' -import type KitRecordTransformer from '#transformers/kit_record_transformer' -import type KitTransformer from '#transformers/kit_transformer' -import type UserTransformer from '#transformers/user_transformer' -import type InertiaMiddleware from '#middleware/inertia_middleware' +import type AuthUserTransformer from '#app/auth/transformers/user_transformer' +import type KitsBuildLogTransformer from '#app/kits/transformers/build_log_transformer' +import type KitsKitRecordTransformer from '#app/kits/transformers/kit_record_transformer' +import type KitsKitTransformer from '#app/kits/transformers/kit_transformer' +import type InertiaMiddleware from '#core/middleware/inertia_middleware' export namespace Data { - export type BuildLog = InferData - export namespace BuildLog { - export type Variants = InferVariants + export namespace Auth { + export type User = InferData + export namespace User { + export type Variants = InferVariants + } } - export type KitRecord = InferData - export namespace KitRecord { - export type Variants = InferVariants - } - export type Kit = InferData - export namespace Kit { - export type Variants = InferVariants - } - export type User = InferData - export namespace User { - export type Variants = InferVariants + export namespace Kits { + export type BuildLog = InferData + export namespace BuildLog { + export type Variants = InferVariants + } + export type KitRecord = InferData + export namespace KitRecord { + export type Variants = InferVariants + } + export type Kit = InferData + export namespace Kit { + export type Variants = InferVariants + } } export type SharedProps = InferSharedProps export type FlashMessages = InferFlashData diff --git a/.adonisjs/client/registry/index.ts b/.adonisjs/client/registry/index.ts index 9b337f3..4d0d408 100644 --- a/.adonisjs/client/registry/index.ts +++ b/.adonisjs/client/registry/index.ts @@ -12,12 +12,6 @@ const routes = { tokens: [{"old":"/","type":0,"val":"/","end":""}], types: placeholder as Registry['home']['types'], }, - 'profile': { - methods: ["GET","HEAD"], - pattern: '/profile/:handle', - tokens: [{"old":"/profile/:handle","type":0,"val":"profile","end":""},{"old":"/profile/:handle","type":1,"val":"handle","end":""}], - types: placeholder as Registry['profile']['types'], - }, 'login': { methods: ["GET","HEAD"], pattern: '/login', @@ -78,6 +72,12 @@ const routes = { tokens: [{"old":"/kits/:rkey","type":0,"val":"kits","end":""},{"old":"/kits/:rkey","type":1,"val":"rkey","end":""}], types: placeholder as Registry['kits.update']['types'], }, + 'profile': { + methods: ["GET","HEAD"], + pattern: '/profile/:handle', + tokens: [{"old":"/profile/:handle","type":0,"val":"profile","end":""},{"old":"/profile/:handle","type":1,"val":"handle","end":""}], + types: placeholder as Registry['profile']['types'], + }, 'event_stream': { methods: ["GET","HEAD"], pattern: '/__transmit/events', diff --git a/.adonisjs/client/registry/schema.d.ts b/.adonisjs/client/registry/schema.d.ts index c0e9bed..21cc446 100644 --- a/.adonisjs/client/registry/schema.d.ts +++ b/.adonisjs/client/registry/schema.d.ts @@ -15,20 +15,8 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> - } - } - 'profile': { - methods: ["GET","HEAD"] - pattern: '/profile/:handle' - types: { - body: {} - paramsTuple: [ParamValue] - params: { handle: ParamValue } - query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'login': { @@ -39,8 +27,8 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: unknown - errorResponse: unknown + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'oauth.logout': { @@ -51,32 +39,32 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'oauth.login': { methods: ["POST"] pattern: '/oauth/login' types: { - body: ExtractBody> + body: ExtractBody> paramsTuple: [] params: {} - query: ExtractQuery> - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } + query: ExtractQuery> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } } } 'oauth.signup': { methods: ["POST"] pattern: '/oauth/signup' types: { - body: ExtractBody> + body: ExtractBody> paramsTuple: [] params: {} - query: ExtractQuery> - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } + query: ExtractQuery> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } } } 'oauth.callback': { @@ -87,8 +75,8 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'dashboard': { @@ -99,8 +87,8 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'kits.new': { @@ -111,20 +99,20 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'kits.store': { methods: ["POST"] pattern: '/kits' types: { - body: ExtractBody> + body: ExtractBody> paramsTuple: [] params: {} - query: ExtractQuery> - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } + query: ExtractQuery> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } } } 'kits.edit': { @@ -135,20 +123,32 @@ export interface Registry { paramsTuple: [ParamValue] params: { rkey: ParamValue } query: {} - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'kits.update': { methods: ["PUT"] pattern: '/kits/:rkey' types: { - body: ExtractBody> + body: ExtractBody> paramsTuple: [ParamValue] params: { rkey: ParamValue } - query: ExtractQuery> - response: ExtractResponse>> - errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } + query: ExtractQuery> + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } } + } + } + 'profile': { + methods: ["GET","HEAD"] + pattern: '/profile/:handle' + types: { + body: {} + paramsTuple: [ParamValue] + params: { handle: ParamValue } + query: {} + response: ExtractResponse>> + errorResponse: ExtractErrorResponse>> } } 'event_stream': { diff --git a/.adonisjs/client/registry/tree.d.ts b/.adonisjs/client/registry/tree.d.ts index de11eb5..249a693 100644 --- a/.adonisjs/client/registry/tree.d.ts +++ b/.adonisjs/client/registry/tree.d.ts @@ -3,7 +3,6 @@ import type { routes } from './index.ts' export interface ApiDefinition { home: typeof routes['home'] - profile: typeof routes['profile'] login: typeof routes['login'] oauth: { logout: typeof routes['oauth.logout'] @@ -18,6 +17,7 @@ export interface ApiDefinition { edit: typeof routes['kits.edit'] update: typeof routes['kits.update'] } + profile: typeof routes['profile'] eventStream: typeof routes['event_stream'] subscribe: typeof routes['subscribe'] unsubscribe: typeof routes['unsubscribe'] diff --git a/.adonisjs/server/controllers.ts b/.adonisjs/server/controllers.ts index 69ccb3b..78a45bd 100644 --- a/.adonisjs/server/controllers.ts +++ b/.adonisjs/server/controllers.ts @@ -4,8 +4,21 @@ */ export const controllers = { - Home: () => import('#controllers/home_controller'), - Kits: () => import('#controllers/kits_controller'), - Oauth: () => import('#controllers/oauth_controller'), - Profile: () => import('#controllers/profile_controller'), + auth: { + Callback: () => import('#app/auth/controllers/callback_controller'), + Login: () => import('#app/auth/controllers/login_controller'), + Logout: () => import('#app/auth/controllers/logout_controller'), + Signup: () => import('#app/auth/controllers/signup_controller'), + }, + feed: { + Feed: () => import('#app/feed/controllers/feed_controller'), + }, + kits: { + ListKits: () => import('#app/kits/controllers/list_kits_controller'), + StoreKit: () => import('#app/kits/controllers/store_kit_controller'), + UpdateKit: () => import('#app/kits/controllers/update_kit_controller'), + }, + profile: { + ShowProfile: () => import('#app/profile/controllers/show_profile_controller'), + }, } diff --git a/.adonisjs/server/routes.d.ts b/.adonisjs/server/routes.d.ts index 3abb7c2..e0e0621 100644 --- a/.adonisjs/server/routes.d.ts +++ b/.adonisjs/server/routes.d.ts @@ -5,7 +5,6 @@ type ParamValue = string | number | bigint | boolean export type ScannedRoutes = { ALL: { 'home': { paramsTuple?: []; params?: {} } - 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'login': { paramsTuple?: []; params?: {} } 'oauth.logout': { paramsTuple?: []; params?: {} } 'oauth.login': { paramsTuple?: []; params?: {} } @@ -16,28 +15,29 @@ export type ScannedRoutes = { 'kits.store': { paramsTuple?: []; params?: {} } 'kits.edit': { paramsTuple: [ParamValue]; params: {'rkey': ParamValue} } 'kits.update': { paramsTuple: [ParamValue]; params: {'rkey': ParamValue} } + 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'event_stream': { paramsTuple?: []; params?: {} } 'subscribe': { paramsTuple?: []; params?: {} } 'unsubscribe': { paramsTuple?: []; params?: {} } } GET: { 'home': { paramsTuple?: []; params?: {} } - 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'login': { paramsTuple?: []; params?: {} } 'oauth.callback': { paramsTuple?: []; params?: {} } 'dashboard': { paramsTuple?: []; params?: {} } 'kits.new': { paramsTuple?: []; params?: {} } 'kits.edit': { paramsTuple: [ParamValue]; params: {'rkey': ParamValue} } + 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'event_stream': { paramsTuple?: []; params?: {} } } HEAD: { 'home': { paramsTuple?: []; params?: {} } - 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'login': { paramsTuple?: []; params?: {} } 'oauth.callback': { paramsTuple?: []; params?: {} } 'dashboard': { paramsTuple?: []; params?: {} } 'kits.new': { paramsTuple?: []; params?: {} } 'kits.edit': { paramsTuple: [ParamValue]; params: {'rkey': ParamValue} } + 'profile': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 'event_stream': { paramsTuple?: []; params?: {} } } POST: { diff --git a/.gitignore b/.gitignore index f71f559..a955375 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ yarn-error.log # Platform specific .DS_Store + +# Notes +.notes diff --git a/adonisrc.ts b/adonisrc.ts index 65a5b2d..ba3f19d 100644 --- a/adonisrc.ts +++ b/adonisrc.ts @@ -130,7 +130,20 @@ export default defineConfig({ hooks: { init: [ indexEntities({ - transformers: { enabled: true, withSharedProps: true }, + controllers: { + enabled: true, + source: './app', + glob: ['**/*_controller.ts'], + importAlias: '#app', + }, + transformers: { + enabled: true, + source: './app', + glob: ['**/*_transformer.ts'], + importAlias: '#app', + withSharedProps: true, + inertiaMiddlewareImportPath: '#core/middleware/inertia_middleware', + }, }), indexPages({ framework: 'react' }), generateRegistry(), diff --git a/app/auth/controllers/callback_controller.ts b/app/auth/controllers/callback_controller.ts new file mode 100644 index 0000000..02c1650 --- /dev/null +++ b/app/auth/controllers/callback_controller.ts @@ -0,0 +1,18 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { AuthService } from '#auth/services/auth_service' + +@inject() +export default class CallbackController { + constructor(private authService: AuthService) {} + + async handle({ response, logger }: HttpContext) { + try { + await this.authService.handleCallback() + return response.redirect().toRoute('dashboard') + } catch (err) { + logger.error(err, 'Error completing AT Protocol OAuth flow') + return response.redirect().toRoute('login') + } + } +} diff --git a/app/auth/controllers/login_controller.ts b/app/auth/controllers/login_controller.ts new file mode 100644 index 0000000..7d481d0 --- /dev/null +++ b/app/auth/controllers/login_controller.ts @@ -0,0 +1,28 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { OAuthResolverError } from '@atproto/oauth-client-node' +import { loginRequestValidator } from '#auth/validators/oauth' +import { AuthService } from '#auth/services/auth_service' + +@inject() +export default class LoginController { + constructor(private authService: AuthService) {} + + async render({ inertia }: HttpContext) { + return inertia.render('auth/login', {}) + } + + async handle({ request, response, inertia, logger }: HttpContext) { + const { input } = await request.validateUsing(loginRequestValidator) + try { + const authorizationUrl = await this.authService.authorize(input) + inertia.location(authorizationUrl) + } catch (err) { + logger.error(err, 'Error starting AT Protocol OAuth flow') + if (err instanceof OAuthResolverError) { + // Handle the input not being AT Protocol OAuth compatible + } + return response.redirect().back() + } + } +} diff --git a/app/auth/controllers/logout_controller.ts b/app/auth/controllers/logout_controller.ts new file mode 100644 index 0000000..9017ef0 --- /dev/null +++ b/app/auth/controllers/logout_controller.ts @@ -0,0 +1,13 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { AuthService } from '#auth/services/auth_service' + +@inject() +export default class LogoutController { + constructor(private authService: AuthService) {} + + async handle({ response }: HttpContext) { + await this.authService.logout() + return response.redirect().back() + } +} diff --git a/app/auth/controllers/signup_controller.ts b/app/auth/controllers/signup_controller.ts new file mode 100644 index 0000000..00b39ba --- /dev/null +++ b/app/auth/controllers/signup_controller.ts @@ -0,0 +1,22 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { signupRequestValidator } from '#auth/validators/oauth' +import { AuthService } from '#auth/services/auth_service' + +@inject() +export default class SignupController { + constructor(private authService: AuthService) {} + + async handle({ request, response, inertia }: HttpContext) { + const { input } = await request.validateUsing(signupRequestValidator) + const service = input ?? 'https://bsky.social' + const registrationSupported = await this.authService.canRegister(service) + + if (!registrationSupported) { + return response.abort('Registration not supported') + } + + const authorizationUrl = await this.authService.register(service) + inertia.location(authorizationUrl) + } +} diff --git a/app/models/oauth_session.ts b/app/auth/models/oauth_session.ts similarity index 100% rename from app/models/oauth_session.ts rename to app/auth/models/oauth_session.ts diff --git a/app/models/oauth_state.ts b/app/auth/models/oauth_state.ts similarity index 100% rename from app/models/oauth_state.ts rename to app/auth/models/oauth_state.ts diff --git a/app/models/user.ts b/app/auth/models/user.ts similarity index 100% rename from app/models/user.ts rename to app/auth/models/user.ts diff --git a/app/auth/routes.ts b/app/auth/routes.ts new file mode 100644 index 0000000..ff17b99 --- /dev/null +++ b/app/auth/routes.ts @@ -0,0 +1,26 @@ +import router from '@adonisjs/core/services/router' +import { middleware } from '#start/kernel' +import { controllers } from '#generated/controllers' + +const { + auth: { + Login: LoginController, + Signup: SignupController, + Callback: CallbackController, + Logout: LogoutController, + }, +} = controllers + +router + .group(() => { + router.get('/login', [LoginController, 'render']).as('login') + }) + .use(middleware.guest()) + +router.post('/oauth/logout', [LogoutController, 'handle']).as('oauth.logout').use(middleware.auth()) + +router.group(() => { + router.post('/oauth/login', [LoginController, 'handle']).as('oauth.login') + router.post('/oauth/signup', [SignupController, 'handle']).as('oauth.signup') + router.get('/oauth/callback', [CallbackController, 'handle']).as('oauth.callback') +}) diff --git a/app/auth/services/auth_service.ts b/app/auth/services/auth_service.ts new file mode 100644 index 0000000..89ef48c --- /dev/null +++ b/app/auth/services/auth_service.ts @@ -0,0 +1,32 @@ +import { inject } from '@adonisjs/core' +import { HttpContext } from '@adonisjs/core/http' + +@inject() +export class AuthService { + constructor(private ctx: HttpContext) {} + + async authorize(input: string) { + return this.ctx.oauth.authorize(input) + } + + async canRegister(service: string) { + return this.ctx.oauth.canRegister(service) + } + + async register(service: string) { + return this.ctx.oauth.register(service) + } + + async handleCallback() { + const session = await this.ctx.oauth.handleCallback() + await this.ctx.auth.use('web').login(session.user) + return session + } + + async logout() { + if (this.ctx.auth.user?.did) { + await this.ctx.oauth.logout(this.ctx.auth.user.did) + } + await this.ctx.auth.use('web').logout() + } +} diff --git a/app/transformers/user_transformer.ts b/app/auth/transformers/user_transformer.ts similarity index 87% rename from app/transformers/user_transformer.ts rename to app/auth/transformers/user_transformer.ts index c772ff7..145a46f 100644 --- a/app/transformers/user_transformer.ts +++ b/app/auth/transformers/user_transformer.ts @@ -1,4 +1,4 @@ -import type User from '#models/user' +import type User from '#auth/models/user' import { BaseTransformer } from '@adonisjs/core/transformers' export default class UserTransformer extends BaseTransformer { diff --git a/app/validators/oauth.ts b/app/auth/validators/oauth.ts similarity index 100% rename from app/validators/oauth.ts rename to app/auth/validators/oauth.ts diff --git a/app/validators/user.ts b/app/auth/validators/user.ts similarity index 100% rename from app/validators/user.ts rename to app/auth/validators/user.ts diff --git a/app/controllers/home_controller.ts b/app/controllers/home_controller.ts deleted file mode 100644 index a63325f..0000000 --- a/app/controllers/home_controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { HttpContext } from '@adonisjs/core/http' -import Kit from '#models/kit' -import KitTransformer from '#transformers/kit_transformer' - -export default class HomeController { - async index({ inertia }: HttpContext) { - const kits = await Kit.query().orderBy('indexed_at', 'desc').limit(50) - return inertia.render('home', { - kits: KitTransformer.transform(kits), - }) - } -} diff --git a/app/controllers/kits_controller.ts b/app/controllers/kits_controller.ts deleted file mode 100644 index c894d33..0000000 --- a/app/controllers/kits_controller.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { HttpContext } from '@adonisjs/core/http' -import { l } from '@atproto/lex' -import gunplaKit from '#lexicons/build/gunpla/kit' -import Kit from '#models/kit' -import { createKitValidator, updateKitValidator } from '#validators/kit' -import KitRecordTransformer from '#transformers/kit_record_transformer' -import { DateTime } from 'luxon' - -export default class KitsController { - async index({ auth, inertia }: HttpContext) { - const { records } = await auth.user!.client.list(gunplaKit) - const kits = KitRecordTransformer.transform( - records.filter((r) => r.valid).map((r) => ({ uri: r.uri as string, value: r.value })) - ) - return inertia.render('dashboard', { kits }) - } - - async new({ inertia }: HttpContext) { - return inertia.render('kits/new', {}) - } - - async store({ request, auth, response, session }: HttpContext) { - const data = await request.validateUsing(createKitValidator) - - const record = await auth.user!.client.create(gunplaKit, { - ...data, - createdAt: l.currentDatetimeString(), - }) - - const existingKit = await Kit.query() - .where('did', auth.user!.did) - .whereNotNull('handle') - .first() - const handle = existingKit?.handle ?? null - - await Kit.updateOrCreate( - { uri: record.uri }, - { - did: auth.user!.did, - handle, - name: data.name, - grade: data.grade ?? null, - scale: data.scale ?? null, - status: data.status, - recordCreatedAt: DateTime.now(), - indexedAt: DateTime.now(), - } - ) - - session.flash('success', `Kit "${data.name}" added to your shelf`) - return response.redirect().toRoute('dashboard') - } - - async edit({ params, auth, inertia, response }: HttpContext) { - const rkey = params.rkey as string - - try { - const remote = await auth.user!.client.get(gunplaKit, { rkey }) - return inertia.render('kits/edit', { - kit: { - rkey, - uri: remote.uri, - name: remote.value.name, - grade: remote.value.grade ?? '', - scale: remote.value.scale ?? '', - status: remote.value.status, - }, - }) - } catch { - return response.notFound('Kit not found') - } - } - - async update({ params, request, auth, response, session }: HttpContext) { - const rkey = params.rkey as string - const data = await request.validateUsing(updateKitValidator) - - try { - const remote = await auth.user!.client.get(gunplaKit, { rkey }) - const val = remote.value - - const updatedVal = { - ...val, - name: data.name, - status: data.status, - grade: data.grade || undefined, - scale: data.scale || undefined, - } - - if (data.status === 'in-progress' && !val.startedAt) { - updatedVal.startedAt = l.currentDatetimeString() - } else if (data.status === 'done' && !val.completedAt) { - updatedVal.completedAt = l.currentDatetimeString() - } - - await auth.user!.client.put(gunplaKit, updatedVal, { rkey }) - - const kitUri = `at://${auth.user!.did}/build.gunpla.kit/${rkey}` - await Kit.query() - .where('uri', kitUri) - .update({ - name: data.name, - status: data.status, - grade: data.grade || null, - scale: data.scale || null, - }) - - session.flash('success', `Updated "${data.name}"`) - return response.redirect().toRoute('dashboard') - } catch { - session.flash('error', 'Failed to update kit on ATProto') - return response.redirect().back() - } - } -} diff --git a/app/controllers/oauth_controller.ts b/app/controllers/oauth_controller.ts deleted file mode 100644 index 7333a1f..0000000 --- a/app/controllers/oauth_controller.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { HttpContext } from '@adonisjs/core/http' -import { OAuthResolverError } from '@atproto/oauth-client-node' -import { loginRequestValidator, signupRequestValidator } from '#validators/oauth' - -export default class OAuthController { - async login({ request, response, inertia, oauth, logger }: HttpContext) { - // input should be a handle or service URL: - const { input } = await request.validateUsing(loginRequestValidator) - try { - const authorizationUrl = await oauth.authorize(input) - - inertia.location(authorizationUrl) - } catch (err) { - logger.error(err, 'Error starting AT Protocol OAuth flow') - if (err instanceof OAuthResolverError) { - // Handle the input not being AT Protocol OAuth compatible - } - - response.redirect().back() - } - } - - async signup({ request, response, inertia, oauth }: HttpContext) { - // input should be a service URL: - const { input } = await request.validateUsing(signupRequestValidator) - const service = input ?? 'https://bsky.social' - const registrationSupported = await oauth.canRegister(service) - - if (!registrationSupported) { - // Handle registration not supported, you may want to special case for - // bsky.social which has public registration behind a click. - - return response.abort('Registration not supported') - } - - const authorizationUrl = await oauth.register(service) - - inertia.location(authorizationUrl) - } - - async logout({ auth, oauth, response }: HttpContext) { - await oauth.logout(auth.user?.did) - await auth.use('web').logout() - - return response.redirect().back() - } - - async callback({ response, oauth, auth, logger }: HttpContext) { - try { - const session = await oauth.handleCallback() - - await auth.use('web').login(session.user) - - // You'll probably want to check if you have an "account" according to Tap - // or some other method, and if not redirect to an onboarding flow - - return response.redirect().toRoute('dashboard') - } catch (err) { - // Handle OAuth failing - logger.error(err, 'Error completing AT Protocol OAuth flow') - - return response.redirect().toRoute('login') - } - } -} diff --git a/app/controllers/profile_controller.ts b/app/controllers/profile_controller.ts deleted file mode 100644 index a2209f8..0000000 --- a/app/controllers/profile_controller.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { HttpContext } from '@adonisjs/core/http' -import Kit from '#models/kit' -import BuildLog from '#models/build_log' -import KitTransformer from '#transformers/kit_transformer' -import BuildLogTransformer from '#transformers/build_log_transformer' - -export default class ProfileController { - async show({ params, inertia }: HttpContext) { - const handle = params.handle as string - const [kits, buildLogs] = await Promise.all([ - Kit.query().where('handle', handle).orderBy('indexed_at', 'desc').limit(100), - BuildLog.query().where('handle', handle).orderBy('indexed_at', 'desc').limit(50), - ]) - return inertia.render('profile', { - handle, - kits: KitTransformer.transform(kits), - buildLogs: BuildLogTransformer.transform(buildLogs), - }) - } -} diff --git a/app/exceptions/handler.ts b/app/core/exceptions/handler.ts similarity index 100% rename from app/exceptions/handler.ts rename to app/core/exceptions/handler.ts diff --git a/app/middleware/auth_middleware.ts b/app/core/middleware/auth_middleware.ts similarity index 77% rename from app/middleware/auth_middleware.ts rename to app/core/middleware/auth_middleware.ts index f5a2ba3..4bf594a 100644 --- a/app/middleware/auth_middleware.ts +++ b/app/core/middleware/auth_middleware.ts @@ -1,6 +1,7 @@ import type { HttpContext } from '@adonisjs/core/http' import type { NextFn } from '@adonisjs/core/types/http' import type { Authenticators } from '@adonisjs/auth/types' +import { AtprotoUser } from '@thisismissem/adonisjs-atproto-oauth' /** * Auth middleware is used authenticate HTTP requests and deny @@ -20,6 +21,11 @@ export default class AuthMiddleware { } = {} ) { await ctx.auth.authenticateUsing(options.guards, { loginRoute: this.redirectTo }) + + if (ctx.auth.user instanceof AtprotoUser) { + ctx.containerResolver.bindValue(AtprotoUser, ctx.auth.user) + } + return next() } } diff --git a/app/middleware/container_bindings_middleware.ts b/app/core/middleware/container_bindings_middleware.ts similarity index 100% rename from app/middleware/container_bindings_middleware.ts rename to app/core/middleware/container_bindings_middleware.ts diff --git a/app/middleware/guest_middleware.ts b/app/core/middleware/guest_middleware.ts similarity index 100% rename from app/middleware/guest_middleware.ts rename to app/core/middleware/guest_middleware.ts diff --git a/app/middleware/inertia_middleware.ts b/app/core/middleware/inertia_middleware.ts similarity index 100% rename from app/middleware/inertia_middleware.ts rename to app/core/middleware/inertia_middleware.ts diff --git a/app/middleware/silent_auth_middleware.ts b/app/core/middleware/silent_auth_middleware.ts similarity index 100% rename from app/middleware/silent_auth_middleware.ts rename to app/core/middleware/silent_auth_middleware.ts diff --git a/start/routes/internal.ts b/app/core/routes.ts similarity index 77% rename from start/routes/internal.ts rename to app/core/routes.ts index 0d71b9e..3924652 100644 --- a/start/routes/internal.ts +++ b/app/core/routes.ts @@ -5,6 +5,8 @@ import env from '#start/env' // Register Server-Sent Events routes for Transmit transmit.registerRoutes() +type BroadcastPayload = Parameters[1] + // Internal broadcast endpoint for worker container router.post('/internal/broadcast', async ({ request, response }) => { const secret = request.header('x-internal-secret') @@ -13,10 +15,10 @@ router.post('/internal/broadcast', async ({ request, response }) => { } const { channel, payload } = request.body() as { channel?: string - payload?: Record + payload?: BroadcastPayload } - if (channel) { - transmit.broadcast(channel, (payload ?? {}) as any) + if (channel && payload !== undefined) { + transmit.broadcast(channel, payload) } return response.ok({ broadcasted: true }) }) diff --git a/app/feed/controllers/feed_controller.ts b/app/feed/controllers/feed_controller.ts new file mode 100644 index 0000000..242e529 --- /dev/null +++ b/app/feed/controllers/feed_controller.ts @@ -0,0 +1,13 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { FeedService } from '#feed/services/feed_service' + +@inject() +export default class FeedController { + constructor(private feedService: FeedService) {} + + async render({ inertia }: HttpContext) { + const kits = await this.feedService.getRecentKits(50) + return inertia.render('home', { kits }) + } +} diff --git a/app/feed/routes.ts b/app/feed/routes.ts new file mode 100644 index 0000000..e358506 --- /dev/null +++ b/app/feed/routes.ts @@ -0,0 +1,8 @@ +import router from '@adonisjs/core/services/router' +import { controllers } from '#generated/controllers' + +const { + feed: { Feed: FeedController }, +} = controllers + +router.get('/', [FeedController, 'render']).as('home') diff --git a/app/feed/services/feed_service.ts b/app/feed/services/feed_service.ts new file mode 100644 index 0000000..985898e --- /dev/null +++ b/app/feed/services/feed_service.ts @@ -0,0 +1,9 @@ +import Kit from '#kits/models/kit' +import KitTransformer from '#kits/transformers/kit_transformer' + +export class FeedService { + async getRecentKits(limit = 50) { + const kits = await Kit.query().orderBy('indexed_at', 'desc').limit(limit) + return KitTransformer.transform(kits) + } +} diff --git a/app/kits/controllers/list_kits_controller.ts b/app/kits/controllers/list_kits_controller.ts new file mode 100644 index 0000000..3a7c0a8 --- /dev/null +++ b/app/kits/controllers/list_kits_controller.ts @@ -0,0 +1,13 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { KitsService } from '#kits/services/kits_service' + +@inject() +export default class ListKitsController { + constructor(private kitsService: KitsService) {} + + async render({ inertia }: HttpContext) { + const kits = await this.kitsService.listForUser() + return inertia.render('dashboard', { kits }) + } +} diff --git a/app/kits/controllers/store_kit_controller.ts b/app/kits/controllers/store_kit_controller.ts new file mode 100644 index 0000000..875038b --- /dev/null +++ b/app/kits/controllers/store_kit_controller.ts @@ -0,0 +1,22 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { createKitValidator } from '#kits/validators/kit' +import { KitsService } from '#kits/services/kits_service' + +@inject() +export default class StoreKitController { + constructor(private kitsService: KitsService) {} + + async render({ inertia }: HttpContext) { + return inertia.render('kits/new', {}) + } + + async handle({ request, response, session }: HttpContext) { + const data = await request.validateUsing(createKitValidator) + + await this.kitsService.create(data) + + session.flash('success', `Kit "${data.name}" added to your shelf`) + return response.redirect().toRoute('dashboard') + } +} diff --git a/app/kits/controllers/update_kit_controller.ts b/app/kits/controllers/update_kit_controller.ts new file mode 100644 index 0000000..052cd32 --- /dev/null +++ b/app/kits/controllers/update_kit_controller.ts @@ -0,0 +1,44 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { updateKitValidator } from '#kits/validators/kit' +import { KitsService } from '#kits/services/kits_service' + +@inject() +export default class UpdateKitController { + constructor(private kitsService: KitsService) {} + + async render({ params, inertia, response }: HttpContext) { + const rkey = params.rkey as string + + try { + const remote = await this.kitsService.getByRkey(rkey) + return inertia.render('kits/edit', { + kit: { + rkey, + uri: remote.uri, + name: remote.value.name, + grade: remote.value.grade ?? '', + scale: remote.value.scale ?? '', + status: remote.value.status, + }, + }) + } catch { + return response.notFound('Kit not found') + } + } + + async handle({ params, request, response, session }: HttpContext) { + const rkey = params.rkey as string + const data = await request.validateUsing(updateKitValidator) + + try { + await this.kitsService.update(rkey, data) + + session.flash('success', `Updated "${data.name}"`) + return response.redirect().toRoute('dashboard') + } catch { + session.flash('error', 'Failed to update kit on ATProto') + return response.redirect().back() + } + } +} diff --git a/app/models/build_log.ts b/app/kits/models/build_log.ts similarity index 100% rename from app/models/build_log.ts rename to app/kits/models/build_log.ts diff --git a/app/models/kit.ts b/app/kits/models/kit.ts similarity index 100% rename from app/models/kit.ts rename to app/kits/models/kit.ts diff --git a/app/kits/routes.ts b/app/kits/routes.ts new file mode 100644 index 0000000..17fdd49 --- /dev/null +++ b/app/kits/routes.ts @@ -0,0 +1,21 @@ +import router from '@adonisjs/core/services/router' +import { middleware } from '#start/kernel' +import { controllers } from '#generated/controllers' + +const { + kits: { + ListKits: ListKitsController, + StoreKit: StoreKitController, + UpdateKit: UpdateKitController, + }, +} = controllers + +router + .group(() => { + router.get('/dashboard', [ListKitsController, 'render']).as('dashboard') + router.get('/kits/new', [StoreKitController, 'render']).as('kits.new') + router.post('/kits', [StoreKitController, 'handle']).as('kits.store') + router.get('/kits/:rkey/edit', [UpdateKitController, 'render']).as('kits.edit') + router.put('/kits/:rkey', [UpdateKitController, 'handle']).as('kits.update') + }) + .use(middleware.auth()) diff --git a/app/kits/services/kits_service.ts b/app/kits/services/kits_service.ts new file mode 100644 index 0000000..7c823d8 --- /dev/null +++ b/app/kits/services/kits_service.ts @@ -0,0 +1,86 @@ +import { inject } from '@adonisjs/core' +import { AtprotoUser } from '@thisismissem/adonisjs-atproto-oauth' +import { l } from '@atproto/lex' +import { DateTime } from 'luxon' +import gunplaKit from '#lexicons/build/gunpla/kit' +import Kit from '#kits/models/kit' +import KitRecordTransformer from '#kits/transformers/kit_record_transformer' +import type { Main } from '#lexicons/build/gunpla/kit.defs' +import type { Infer } from '@vinejs/vine/types' +import type { createKitValidator, updateKitValidator } from '#kits/validators/kit' + +@inject() +export class KitsService { + constructor(protected user: AtprotoUser) {} + + async listForUser() { + const { records } = await this.user.client.list(gunplaKit) + const items: Array<{ uri: string; value: Main }> = records + .filter((r) => r.valid) + .map((r) => ({ uri: r.uri, value: r.value })) + return KitRecordTransformer.transform(items) + } + + async getByRkey(rkey: string) { + return this.user.client.get(gunplaKit, { rkey }) + } + + async create(data: Infer) { + const record = await this.user.client.create(gunplaKit, { + ...data, + createdAt: l.currentDatetimeString(), + }) + + const existingKit = await Kit.query().where('did', this.user.did).whereNotNull('handle').first() + const handle = existingKit?.handle ?? null + + await Kit.updateOrCreate( + { uri: record.uri }, + { + did: this.user.did, + handle, + name: data.name, + grade: data.grade ?? null, + scale: data.scale ?? null, + status: data.status, + recordCreatedAt: DateTime.now(), + indexedAt: DateTime.now(), + } + ) + + return record + } + + async update(rkey: string, data: Infer) { + const remote = await this.user.client.get(gunplaKit, { rkey }) + const val = remote.value + + const updatedVal: typeof val = { + ...val, + name: data.name, + status: data.status, + grade: data.grade || undefined, + scale: data.scale || undefined, + } + + if (data.status === 'in-progress' && !val.startedAt) { + updatedVal.startedAt = l.currentDatetimeString() + } else if (data.status === 'done' && !val.completedAt) { + updatedVal.completedAt = l.currentDatetimeString() + } + + await this.user.client.put(gunplaKit, updatedVal, { rkey }) + + const kitUri = `at://${this.user.did}/build.gunpla.kit/${rkey}` + await Kit.query() + .where('uri', kitUri) + .update({ + name: data.name, + status: data.status, + grade: data.grade || null, + scale: data.scale || null, + }) + + return { uri: kitUri, value: updatedVal } + } +} diff --git a/app/transformers/build_log_transformer.ts b/app/kits/transformers/build_log_transformer.ts similarity index 89% rename from app/transformers/build_log_transformer.ts rename to app/kits/transformers/build_log_transformer.ts index 227b9d2..62aec0c 100644 --- a/app/transformers/build_log_transformer.ts +++ b/app/kits/transformers/build_log_transformer.ts @@ -1,5 +1,5 @@ import { BaseTransformer } from '@adonisjs/core/transformers' -import type BuildLog from '#models/build_log' +import type BuildLog from '#kits/models/build_log' export default class BuildLogTransformer extends BaseTransformer { toObject() { diff --git a/app/transformers/kit_record_transformer.ts b/app/kits/transformers/kit_record_transformer.ts similarity index 100% rename from app/transformers/kit_record_transformer.ts rename to app/kits/transformers/kit_record_transformer.ts diff --git a/app/transformers/kit_transformer.ts b/app/kits/transformers/kit_transformer.ts similarity index 92% rename from app/transformers/kit_transformer.ts rename to app/kits/transformers/kit_transformer.ts index 2d15efb..3f7a423 100644 --- a/app/transformers/kit_transformer.ts +++ b/app/kits/transformers/kit_transformer.ts @@ -1,5 +1,5 @@ import { BaseTransformer } from '@adonisjs/core/transformers' -import type Kit from '#models/kit' +import type Kit from '#kits/models/kit' export default class KitTransformer extends BaseTransformer { toObject() { diff --git a/app/validators/kit.ts b/app/kits/validators/kit.ts similarity index 100% rename from app/validators/kit.ts rename to app/kits/validators/kit.ts diff --git a/app/profile/controllers/show_profile_controller.ts b/app/profile/controllers/show_profile_controller.ts new file mode 100644 index 0000000..fb7484c --- /dev/null +++ b/app/profile/controllers/show_profile_controller.ts @@ -0,0 +1,19 @@ +import { inject } from '@adonisjs/core' +import type { HttpContext } from '@adonisjs/core/http' +import { ProfileService } from '#profile/services/profile_service' + +@inject() +export default class ShowProfileController { + constructor(private profileService: ProfileService) {} + + async render({ params, inertia }: HttpContext) { + const handle = params.handle as string + const { kits, buildLogs } = await this.profileService.getProfileData(handle) + + return inertia.render('profile', { + handle, + kits, + buildLogs, + }) + } +} diff --git a/app/profile/routes.ts b/app/profile/routes.ts new file mode 100644 index 0000000..421564c --- /dev/null +++ b/app/profile/routes.ts @@ -0,0 +1,8 @@ +import router from '@adonisjs/core/services/router' +import { controllers } from '#generated/controllers' + +const { + profile: { ShowProfile: ShowProfileController }, +} = controllers + +router.get('/profile/:handle', [ShowProfileController, 'render']).as('profile') diff --git a/app/profile/services/profile_service.ts b/app/profile/services/profile_service.ts new file mode 100644 index 0000000..e6c3597 --- /dev/null +++ b/app/profile/services/profile_service.ts @@ -0,0 +1,18 @@ +import Kit from '#kits/models/kit' +import BuildLog from '#kits/models/build_log' +import KitTransformer from '#kits/transformers/kit_transformer' +import BuildLogTransformer from '#kits/transformers/build_log_transformer' + +export class ProfileService { + async getProfileData(handle: string) { + const [kits, buildLogs] = await Promise.all([ + Kit.query().where('handle', handle).orderBy('indexed_at', 'desc').limit(100), + BuildLog.query().where('handle', handle).orderBy('indexed_at', 'desc').limit(50), + ]) + + return { + kits: KitTransformer.transform(kits), + buildLogs: BuildLogTransformer.transform(buildLogs), + } + } +} diff --git a/config/atproto_oauth.ts b/config/atproto_oauth.ts index dbf2770..477e059 100644 --- a/config/atproto_oauth.ts +++ b/config/atproto_oauth.ts @@ -32,7 +32,7 @@ export default defineConfig({ jwks: [env.get('ATPROTO_OAUTH_JWT_PRIVATE_KEY')], // Models to store OAuth State and Sessions: stores: { - states: lucidStateStore(() => import('#models/oauth_state')), - sessions: lucidSessionStore(() => import('#models/oauth_session')), + states: lucidStateStore(() => import('#auth/models/oauth_state')), + sessions: lucidSessionStore(() => import('#auth/models/oauth_session')), }, }) diff --git a/inertia/pages/dashboard.tsx b/inertia/pages/dashboard.tsx index 172ada0..b7caee9 100644 --- a/inertia/pages/dashboard.tsx +++ b/inertia/pages/dashboard.tsx @@ -4,7 +4,7 @@ import { Link } from '@adonisjs/inertia/react' import { Plus, Pencil } from 'lucide-react' import type { InertiaProps } from '~/types' import type { InferData } from '@adonisjs/http-transformers/types' -import type KitRecordTransformer from '#transformers/kit_record_transformer' +import type KitRecordTransformer from '#kits/transformers/kit_record_transformer' type KitItem = InferData diff --git a/inertia/pages/home.tsx b/inertia/pages/home.tsx index 6e0d6a5..858b86c 100644 --- a/inertia/pages/home.tsx +++ b/inertia/pages/home.tsx @@ -5,7 +5,7 @@ import { transmit } from '~/services/transmit' import MarketingLayout from '~/layouts/marketing' import type { InertiaProps } from '~/types' import type { InferData } from '@adonisjs/http-transformers/types' -import type KitTransformer from '#transformers/kit_transformer' +import type KitTransformer from '#kits/transformers/kit_transformer' type KitRow = InferData diff --git a/inertia/pages/profile.tsx b/inertia/pages/profile.tsx index 409cc8e..b6512cc 100644 --- a/inertia/pages/profile.tsx +++ b/inertia/pages/profile.tsx @@ -1,8 +1,8 @@ import MarketingLayout from '~/layouts/marketing' import type { InertiaProps } from '~/types' import type { InferData } from '@adonisjs/http-transformers/types' -import type KitTransformer from '#transformers/kit_transformer' -import type BuildLogTransformer from '#transformers/build_log_transformer' +import type KitTransformer from '#kits/transformers/kit_transformer' +import type BuildLogTransformer from '#kits/transformers/build_log_transformer' type KitRow = InferData type BuildLogRow = InferData diff --git a/inertia/tsconfig.json b/inertia/tsconfig.json index d1d10d1..9850403 100644 --- a/inertia/tsconfig.json +++ b/inertia/tsconfig.json @@ -7,7 +7,13 @@ "~/*": ["./*"], "@generated/*": ["../.adonisjs/client/*"], "#models/*": ["../app/models/*"], - "#transformers/*": ["../app/transformers/*"] + "#transformers/*": ["../app/transformers/*"], + "#app/*": ["../app/*"], + "#kits/*": ["../app/kits/*"], + "#auth/*": ["../app/auth/*"], + "#feed/*": ["../app/feed/*"], + "#profile/*": ["../app/profile/*"], + "#core/*": ["../app/core/*"] } }, "include": [ diff --git a/package.json b/package.json index 9a49a65..127c980 100644 --- a/package.json +++ b/package.json @@ -18,16 +18,22 @@ "typecheck": "tsc --noEmit && tsc --noEmit --project inertia/tsconfig.json" }, "imports": { + "#app/*": "./app/*.js", + "#kits/*": "./app/kits/*.js", + "#auth/*": "./app/auth/*.js", + "#feed/*": "./app/feed/*.js", + "#profile/*": "./app/profile/*.js", + "#core/*": "./app/core/*.js", "#lexicons/*": "./app/lexicons/*.js", "#controllers/*": "./app/controllers/*.js", - "#exceptions/*": "./app/exceptions/*.js", + "#exceptions/*": "./app/core/exceptions/*.js", "#models/*": "./app/models/*.js", "#mails/*": "./app/mails/*.js", - "#services/*": "./app/services/*.js", + "#services/*": "./services/*.js", "#listeners/*": "./app/listeners/*.js", "#events/*": "./app/events/*.js", "#generated/*": "./.adonisjs/server/*.js", - "#middleware/*": "./app/middleware/*.js", + "#middleware/*": "./app/core/middleware/*.js", "#transformers/*": "./app/transformers/*.js", "#validators/*": "./app/validators/*.js", "#providers/*": "./providers/*.js", @@ -97,8 +103,8 @@ }, "hotHook": { "boundaries": [ - "./app/controllers/**/*.ts", - "./app/middleware/*.ts" + "./app/**/controllers/**/*.ts", + "./app/**/middleware/**/*.ts" ] }, "allowScripts": { diff --git a/app/services/jetstream_service.ts b/services/jetstream_service.ts similarity index 98% rename from app/services/jetstream_service.ts rename to services/jetstream_service.ts index ebf1607..12c5e37 100644 --- a/app/services/jetstream_service.ts +++ b/services/jetstream_service.ts @@ -1,8 +1,9 @@ import app from '@adonisjs/core/services/app' import logger from '@adonisjs/core/services/logger' +import { inject } from '@adonisjs/core' import env from '#start/env' -import Kit from '#models/kit' -import BuildLog from '#models/build_log' +import Kit from '#kits/models/kit' +import BuildLog from '#kits/models/build_log' import { DateTime } from 'luxon' import fs from 'node:fs' @@ -31,6 +32,7 @@ export interface JetstreamServiceOptions { cursorFilePath?: string } +@inject() export class JetstreamService { private endpoint: string private wantedCollections: string[] diff --git a/start/kernel.ts b/start/kernel.ts index 15ef29b..dc1fe06 100644 --- a/start/kernel.ts +++ b/start/kernel.ts @@ -15,7 +15,7 @@ import server from '@adonisjs/core/services/server' * The error handler is used to convert an exception * to a HTTP response. */ -server.errorHandler(() => import('#exceptions/handler')) +server.errorHandler(() => import('#core/exceptions/handler')) /** * The server middleware stack runs middleware on all the HTTP @@ -23,11 +23,11 @@ server.errorHandler(() => import('#exceptions/handler')) * the request URL. */ server.use([ - () => import('#middleware/container_bindings_middleware'), + () => import('#core/middleware/container_bindings_middleware'), () => import('@adonisjs/static/static_middleware'), () => import('@adonisjs/cors/cors_middleware'), () => import('@adonisjs/vite/vite_middleware'), - () => import('#middleware/inertia_middleware'), + () => import('#core/middleware/inertia_middleware'), ]) /** @@ -39,7 +39,7 @@ router.use([ () => import('@adonisjs/session/session_middleware'), () => import('@adonisjs/shield/shield_middleware'), () => import('@adonisjs/auth/initialize_auth_middleware'), - () => import('#middleware/silent_auth_middleware'), + () => import('#core/middleware/silent_auth_middleware'), () => import('@thisismissem/adonisjs-atproto-oauth/initialize_atproto_auth_middleware'), ]) @@ -48,6 +48,6 @@ router.use([ * the routes or the routes group. */ export const middleware = router.named({ - guest: () => import('#middleware/guest_middleware'), - auth: () => import('#middleware/auth_middleware'), + guest: () => import('#core/middleware/guest_middleware'), + auth: () => import('#core/middleware/auth_middleware'), }) diff --git a/start/routes.ts b/start/routes.ts index 6c820c4..b134ad2 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -7,7 +7,8 @@ | */ -import '#start/routes/internal' -import '#start/routes/web' -import '#start/routes/oauth' -import '#start/routes/kits' +import '#core/routes' +import '#feed/routes' +import '#auth/routes' +import '#kits/routes' +import '#profile/routes' diff --git a/start/routes/kits.ts b/start/routes/kits.ts deleted file mode 100644 index 86c121d..0000000 --- a/start/routes/kits.ts +++ /dev/null @@ -1,13 +0,0 @@ -import router from '@adonisjs/core/services/router' -import { middleware } from '#start/kernel' -import { controllers } from '#generated/controllers' - -router - .group(() => { - router.get('/dashboard', [controllers.Kits, 'index']).as('dashboard') - router.get('/kits/new', [controllers.Kits, 'new']).as('kits.new') - router.post('/kits', [controllers.Kits, 'store']).as('kits.store') - router.get('/kits/:rkey/edit', [controllers.Kits, 'edit']).as('kits.edit') - router.put('/kits/:rkey', [controllers.Kits, 'update']).as('kits.update') - }) - .use(middleware.auth()) diff --git a/start/routes/oauth.ts b/start/routes/oauth.ts deleted file mode 100644 index ecc8ad3..0000000 --- a/start/routes/oauth.ts +++ /dev/null @@ -1,17 +0,0 @@ -import router from '@adonisjs/core/services/router' -import { middleware } from '#start/kernel' -import { controllers } from '#generated/controllers' - -router - .group(() => { - router.on('/login').renderInertia('auth/login', {}).as('login') - }) - .use(middleware.guest()) - -router.post('/oauth/logout', [controllers.Oauth, 'logout']).use(middleware.auth()) - -router.group(() => { - router.post('/oauth/login', [controllers.Oauth, 'login']) - router.post('/oauth/signup', [controllers.Oauth, 'signup']) - router.get('/oauth/callback', [controllers.Oauth, 'callback']) -}) diff --git a/start/routes/web.ts b/start/routes/web.ts deleted file mode 100644 index 1a07ea6..0000000 --- a/start/routes/web.ts +++ /dev/null @@ -1,5 +0,0 @@ -import router from '@adonisjs/core/services/router' -import { controllers } from '#generated/controllers' - -router.get('/', [controllers.Home, 'index']).as('home') -router.get('/profile/:handle', [controllers.Profile, 'show']).as('profile')