-
Notifications
You must be signed in to change notification settings - Fork 17
grpc: Move /posts/<id> to backend #127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 24 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
9a43270
feat(vscode): Add option to rebuild gRPC bindings
ashquarky d6a5d2d
feat(grpc): Move headers into the JSON object
ashquarky f2b6938
fix(grpc): Log the error object
ashquarky a4da331
feat(grpc): helpers for responding with error codes
ashquarky 93e3ad1
feat(grpc): Work-in-progress authentication middleware
ashquarky a4f5153
chore(internal): Refactor error handling
ashquarky c695ef2
feat(internal): Implement authentication and tweak error handling more
ashquarky d9f70e9
feat(internal): Check for banned accounts
ashquarky 06ab562
feat(internal): WIP posts endpoint (auth not working)
ashquarky 2be4de2
fix(ui): Don't crash on promise rejection (please)
ashquarky fc8204c
fix(internal): enable posts route
ashquarky 5c91b11
fix(server): Fix incorrect Express error handler
ashquarky 952c758
feat(internal): Validate and use posts endpoint, tweak tokens handling
ashquarky 771b649
feat(internal): Set up guest access controls per-endpoint
ashquarky 126378b
fix(server): Force re-login if backend rejects user token
ashquarky 9668d68
feat(ui): Support redirecting out of the login page
ashquarky 6d8eced
fix(login): Validate redirect path
ashquarky 70907d2
fix(api): Audit and fix schema to reflect real db
ashquarky 83221c9
fix(login): Validation for the validation gods
ashquarky 4b8ca00
feat(api): Rate-limiting for the ratelimiting gods
ashquarky 299db63
feat(internal): Introduce dto contract type
ashquarky 586e77d
feat(internal): Add explicit nulls for 404s
ashquarky 77d331c
fix(internal): Restructure auth and guard middlewares
ashquarky 5716ddd
Merge branch 'dev' into work/grpc
ashquarky eda12fb
fix(api): Tweak ratelimits
ashquarky e81f230
feat(internal): Stronger checks on account status + mod mode
ashquarky 1e1f0bf
feat(internal): Show moderators removed posts
ashquarky dad0b14
fix(web): Provide redirect on all paths
ashquarky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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,65 @@ | ||
| import { apiFetchUser } from '@/fetch'; | ||
| import type { UserTokens } from '@/fetch'; | ||
|
|
||
| /* !!! HEY | ||
| * This type lives in apps/miiverse-api/src/services/internal/contract/post.ts | ||
| * Modify it there and copy-paste here! */ | ||
|
|
||
| /* This type is the contract for the frontend. If we make changes to the db, this shape should be kept. */ | ||
| export type PostDto = { | ||
| id: string; | ||
| title_id?: string; // number | ||
| screen_name: string; | ||
| body: string; | ||
| app_data?: string; // nintendo base64 | ||
|
|
||
| painting?: string; // base64 or '', undef for PMs | ||
| screenshot?: string; // URL frag (leading /) or '', undef for PMs | ||
| screenshot_length?: number; | ||
|
|
||
| search_key?: string[]; // can be [] | ||
| topic_tag?: string; // can be '' | ||
|
|
||
| community_id: string; // number | ||
| created_at: string; // ISO Z | ||
| feeling_id?: number; | ||
|
|
||
| is_autopost: boolean; | ||
| is_community_private_autopost: boolean; | ||
| is_spoiler: boolean; | ||
| is_app_jumpable: boolean; | ||
|
|
||
| empathy_count: number; | ||
| country_id: number; | ||
| language_id: number; | ||
|
|
||
| mii: string; // nintendo base64 | ||
| mii_face_url: string; // full URL (cdn., r2-cdn.) | ||
|
|
||
| pid: number; | ||
| platform_id?: number; | ||
| region_id?: number; | ||
| parent: string | null; | ||
|
|
||
| reply_count: number; | ||
| verified: boolean; | ||
|
|
||
| message_to_pid: string | null; | ||
| removed: boolean; | ||
| removed_by?: number; | ||
| removed_at?: string; // ISO Z | ||
| removed_reason?: string; | ||
|
|
||
| yeahs: number[]; | ||
| }; | ||
|
|
||
| /** | ||
| * Fetches a Post for a given ID. | ||
| * @param tokens User to perform fetch as. Responses will be according to this users' permissions (user, moderator etc.) | ||
| * @param post_id The ID of the post to get. | ||
| * @returns Post object | ||
| */ | ||
| export async function getPostById(tokens: UserTokens, post_id: string): Promise<PostDto | null> { | ||
| const post = await apiFetchUser<PostDto>(tokens, `/api/v1/posts/${post_id}`); | ||
| return post; | ||
| } |
This file contains hidden or 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 hidden or 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,39 +1,72 @@ | ||
| import { Metadata } from 'nice-grpc'; | ||
| import { config } from '@/config'; | ||
| import { grpcClient } from '@/grpc'; | ||
| import type { PacketResponse } from '@repo/grpc-client/out/packet'; | ||
|
|
||
| export type FetchOptions = { | ||
| method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; | ||
| headers?: Record<string, string>; | ||
| headers?: Record<string, string | undefined>; | ||
| body?: Record<string, any> | undefined | null; | ||
| }; | ||
|
|
||
| export interface FetchError extends Error { | ||
| name: 'FetchError'; | ||
| status: number; | ||
| response: any; | ||
| } | ||
| function FetchError(response: PacketResponse, message: string): FetchError { | ||
| const error = new Error(message) as FetchError; | ||
| error.name = 'FetchError'; | ||
| error.status = response.status; | ||
| error.response = response.payload; // parse json? | ||
| return error; | ||
| } | ||
|
|
||
| function isErrorHttpStatus(status: number): boolean { | ||
| return status >= 400 && status < 600; | ||
| } | ||
|
|
||
| export async function apiFetch<T>(path: string, options?: FetchOptions): Promise<T> { | ||
| export async function apiFetch<T>(path: string, options?: FetchOptions): Promise<T | null> { | ||
| const defaultedOptions = { | ||
| method: 'GET', | ||
| headers: {}, | ||
| ...options | ||
| }; | ||
|
|
||
| const metadata = Metadata({ | ||
| ...defaultedOptions.headers, | ||
| 'X-API-Key': config.grpc.miiverse.apiKey | ||
| }); | ||
| const response = await grpcClient.sendPacket({ | ||
| path, | ||
| method: defaultedOptions.method, | ||
| headers: JSON.stringify(defaultedOptions.headers), | ||
| payload: defaultedOptions.body ? JSON.stringify(defaultedOptions.body) : undefined | ||
| }, { | ||
| metadata | ||
| }); | ||
|
|
||
| if (isErrorHttpStatus(response.status)) { | ||
| throw new Error(`HTTP error! status: ${response.status}`); | ||
| if (response.status === 404) { | ||
| return null; | ||
| } else if (isErrorHttpStatus(response.status)) { | ||
| throw FetchError(response, `HTTP error! status: ${response.status} ${response.payload}`); | ||
| } | ||
|
|
||
| return JSON.parse(response.payload) as T; | ||
| } | ||
|
|
||
| export type UserTokens = { | ||
| serviceToken?: string; | ||
| oauthToken?: string; | ||
| }; | ||
|
|
||
| export async function apiFetchUser<T>(tokens: UserTokens, path: string, options?: FetchOptions): Promise<T | null> { | ||
| options = { | ||
| ...options, | ||
| headers: { | ||
| 'x-service-token': tokens.serviceToken, | ||
| 'x-oauth-token': tokens.oauthToken, | ||
| ...options?.headers | ||
| } | ||
| }; | ||
| return apiFetch<T>(path, options); | ||
| } |
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.