-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
58feb44
commit c199eae
Showing
9 changed files
with
260 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { type Ctx, StatusCode, ValidationType } from '@/endpoints.ts'; | ||
import { z } from 'npm:zod'; | ||
import { OpenAPIDoc } from '@/lib/openAPI.types.ts'; | ||
import { Buffer } from 'node:buffer'; | ||
import { createNewUserIfNeeded, registerParams } from '@/db/models/Users.ts'; | ||
|
||
async function getDataFromGoogle(accessToken: string) { | ||
const url = new URL('https://www.googleapis.com/oauth2/v3/userinfo'); | ||
url.searchParams.append('access_token', accessToken); | ||
|
||
const response = await fetch(url.toString(), { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
|
||
if (!response.ok) { | ||
return { | ||
isError: true, | ||
status: 502, | ||
message: 'Failed to get user data from Google', | ||
}; | ||
} | ||
|
||
const data = await response.json(); | ||
return { | ||
isError: false, | ||
data, | ||
}; | ||
} | ||
|
||
function parseJwt(token: string) { | ||
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); | ||
} | ||
|
||
function getDataFromApple(accessToken: string) { | ||
const JWT = accessToken; | ||
const decoded = parseJwt(JWT); | ||
|
||
const email = decoded.email; | ||
|
||
if (!email) { | ||
return { | ||
isError: true, | ||
status: 400, | ||
message: 'Failed to get email from Apple.', | ||
}; | ||
} | ||
const beforeAt = email.split('@')[0]; | ||
if (!beforeAt || beforeAt.length < 1) { | ||
return { | ||
isError: true, | ||
status: 400, | ||
message: 'Invalid email from Apple.', | ||
}; | ||
} | ||
|
||
const name = beforeAt; | ||
const picture = ''; | ||
|
||
return { | ||
isError: false, | ||
data: { | ||
email, | ||
name, | ||
picture, | ||
}, | ||
}; | ||
} | ||
|
||
export async function POST(ctx: Ctx) { | ||
const requestData = ctx.get('dataValidation').user; | ||
const body: BodyType = requestData.body; | ||
|
||
const registerType: 'google' | 'apple' = body.registerType; | ||
const accessToken = body.accessToken; | ||
|
||
const data = await { | ||
google: getDataFromGoogle, | ||
apple: getDataFromApple, | ||
}[registerType](accessToken); | ||
|
||
if (data.isError) { | ||
return await ctx.json( | ||
{ message: data.message }, | ||
data.status as StatusCode | ||
); | ||
} | ||
|
||
const requiredData: registerParams = { | ||
registerType, | ||
email: data.data.email, | ||
name: data.data.name, | ||
picture: data.data.picture, | ||
}; | ||
|
||
const { token, type } = await createNewUserIfNeeded(ctx, requiredData); | ||
|
||
return await ctx.json( | ||
{ | ||
token, | ||
type, | ||
}, | ||
200 | ||
); | ||
} | ||
|
||
export const path = '/api/register'; | ||
|
||
export const validation: ValidationType = { | ||
body: z.object({ | ||
registerType: z | ||
.string() | ||
.refine( | ||
(v) => ['apple', 'google'].includes(v), | ||
'Invalid registerType, must be "apple" or "google"' | ||
), | ||
accessToken: z.string(), | ||
}), | ||
}; | ||
type BodyType = z.infer<typeof validation.body>; | ||
|
||
export const openAPI: OpenAPIDoc = { | ||
description: 'Register the user', | ||
tags: ['User'], | ||
responses: { | ||
200: { | ||
type: 'application/json', | ||
zodSchema: z.object({ | ||
token: z.string(), | ||
type: z.string(), | ||
}), | ||
}, | ||
400: { | ||
type: 'application/json', | ||
zodSchema: z.object({ | ||
message: z.string(), | ||
}), | ||
}, | ||
502: { | ||
type: 'application/json', | ||
zodSchema: z.object({ | ||
message: z.string(), | ||
}), | ||
}, | ||
}, | ||
}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,58 @@ | ||
import { | ||
type ctx, | ||
type MiddlewareDataArray, | ||
getDataFromMiddleware, | ||
SetResponse, | ||
type Ctx, | ||
ValidationType, | ||
} from '@/endpoints.ts'; | ||
import { IUser } from '@/db/models/Users.ts'; | ||
import { z } from 'npm:zod'; | ||
import { shouldBeUserId } from '@/lib/userIdCheck.ts'; | ||
import { OpenAPIDoc } from "@/lib/openAPI.types.ts"; | ||
|
||
/** | ||
* STEP 1: (OPTIONAL) Do this setting on | ||
* If you using VSCode, enable 'editor.foldingImportsByDefault' to fold imports | ||
* and get better DX. | ||
*/ | ||
|
||
/** | ||
* STEP 2: (REQUIRED) Endpoint path implementation | ||
* Don't forget to add filepath to endpoints.ts's loadEndpoints function's return array. | ||
* Because Deno Deploy don't allow dynamic imports cause of security reasons. | ||
*/ | ||
|
||
/** | ||
* STEP 3: (REQUIRED) Readability | ||
* Don't want create a new file? Create it! Readability is most important thing. | ||
* Split to multiple files if you need. Single Responsibility Principle is base rule. | ||
*/ | ||
|
||
/** | ||
* POST /api/postEvent | ||
* | ||
* What do: Post the event | ||
*/ | ||
export function POST(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void { | ||
// .user means user so developer level which not base(library) level | ||
const authData = getDataFromMiddleware( | ||
_middlewareDatas, | ||
'auth:validToken' | ||
).user; | ||
const user = authData as IUser; | ||
|
||
const requestData = getDataFromMiddleware( | ||
_middlewareDatas, | ||
'dataValidation' | ||
).user; | ||
export async function GET(ctx: Ctx) { | ||
const requestData = ctx.get('dataValidation').user | ||
const query: QueryType = requestData.query; | ||
const body: BodyType = requestData.body; | ||
|
||
console.log('logging', query.eventId); | ||
console.log('Another logging', body.name); | ||
// middleware converts userId to User | ||
const _targetUser = query.userId; | ||
const _name: string = query.name; | ||
const _log: string = body.log; | ||
|
||
return SetResponse(ctx, { | ||
status: 200, | ||
body: { | ||
username: user.username, | ||
}, | ||
}); | ||
} | ||
|
||
/** | ||
* GET /api/postEvent | ||
* | ||
* What do: Get the event | ||
*/ | ||
export function GET(ctx: ctx, _middlewareDatas: MiddlewareDataArray): void { | ||
return SetResponse(ctx, { | ||
status: 200, | ||
body: {}, | ||
}); | ||
// ... | ||
return await ctx.json({message: 'ok'}, 200); | ||
} | ||
|
||
// Configurations | ||
export const pattern = new URLPattern({ pathname: '/api/postEvent' }); | ||
// ! REQUIRED CONFIGURATION BELOW | ||
export const path = '/api/ENDPOINT'; | ||
// ! REQUIRED Endpoint path implementation | ||
// * Don't forget to add filepath to endpoints.ts's loadEndpoints function's return array. | ||
// * Because Deno Deploy don't allow dynamic imports cause of security reasons. | ||
//// //// | ||
|
||
// OPTIONAL CONFIGURATIONS BELOW | ||
export const middlewares = ['auth:validToken']; | ||
|
||
export const validation: ValidationType = { | ||
// Please use for 'GET', 'DELETE', 'OPTIONS' or 'HEAD' | ||
// /api/postEvent?test=anystring | ||
query: { | ||
eventId: z.string().min(4), | ||
name: z.string().min(1), | ||
userId: shouldBeUserId, | ||
}, | ||
|
||
// Please use for 'POST', 'PUT' or 'PATCH' | ||
// /api/postEvent | ||
// { | ||
// name: 'anystring', | ||
// description: 'anystring', | ||
// } | ||
body: z.object({ | ||
name: z.string().min(5), | ||
description: z.string().min(1), | ||
}), | ||
log: z.string().min(1), | ||
}) | ||
}; | ||
export const middlewares = ['auth:validToken']; | ||
|
||
const querySchema = z.object(validation.query as z.ZodRawShape); | ||
type QueryType = z.infer<typeof querySchema>; | ||
type BodyType = z.infer<typeof validation.body>; | ||
|
||
export const openAPI: OpenAPIDoc = { | ||
description: 'Description of the endpoint', | ||
tags: ['Folder Name'], | ||
responses: { | ||
200: { | ||
type: 'application/json', | ||
zodSchema: z.object({ | ||
isError: z.boolean(), | ||
message: z.string().optional(), | ||
}), | ||
}, | ||
}, | ||
} |
Oops, something went wrong.