Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,407 changes: 1,407 additions & 0 deletions generated/schema.graphql

Large diffs are not rendered by default.

1,310 changes: 1,303 additions & 7 deletions generated/schema.ts

Large diffs are not rendered by default.

78,510 changes: 40,190 additions & 38,320 deletions generated/types.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
table:
name: broadcast_huds
schema: public
select_permissions:
- role: guest
permission:
columns:
- id
- slug
- jthud_id
- variant
- name
- author
- version
- description
- source
- enabled
- thumbnail
- preview
- page_url
- is_signed
- created_at
- updated_at
filter:
enabled:
_eq: true
comment: ""
- role: administrator
permission:
columns:
- id
- slug
- jthud_id
- variant
- name
- author
- version
- description
- source
- enabled
- storage_key
- size_bytes
- thumbnail
- preview
- page_url
- hud_json
- is_signed
- uploaded_by_steam_id
- created_at
- updated_at
filter: {}
comment: ""
update_permissions:
- role: administrator
permission:
columns:
- name
- description
- enabled
filter: {}
check: {}
comment: ""
delete_permissions:
- role: administrator
permission:
filter:
source:
_eq: imported
comment: ""
1 change: 1 addition & 0 deletions hasura/metadata/databases/default/tables/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- "!include public_api_keys.yaml"
- "!include public_award_recipients.yaml"
- "!include public_awards.yaml"
- "!include public_broadcast_huds.yaml"
- "!include public_chat_read_state.yaml"
- "!include public_clip_render_jobs.yaml"
- "!include public_custom_pages.yaml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS public.broadcast_huds;
60 changes: 60 additions & 0 deletions hasura/migrations/default/1887000000300_broadcast_huds/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
CREATE TABLE IF NOT EXISTS public.broadcast_huds (
id uuid NOT NULL DEFAULT gen_random_uuid(),
slug text NOT NULL,
jthud_id text NOT NULL,
variant text,
name text NOT NULL,
author text,
version text,
description text,
source text NOT NULL DEFAULT 'imported',
enabled boolean NOT NULL DEFAULT true,
storage_key text,
size_bytes bigint,
thumbnail text,
preview text,
page_url text,
hud_json jsonb,
is_signed boolean NOT NULL DEFAULT false,
uploaded_by_steam_id bigint REFERENCES public.players (steam_id)
ON UPDATE CASCADE ON DELETE SET NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now(),

PRIMARY KEY (id),
UNIQUE (slug),

CONSTRAINT broadcast_huds_slug_is_path_safe
CHECK (slug ~ '^[a-z0-9]+(?:-[a-z0-9]+)*$'),

CONSTRAINT broadcast_huds_jthud_id_is_path_safe
CHECK (jthud_id ~ '^[A-Za-z0-9_-]+$'),

CONSTRAINT broadcast_huds_source_is_known
CHECK (source IN ('builtin', 'imported')),

CONSTRAINT broadcast_huds_archive_matches_source
CHECK (
(source = 'builtin' AND storage_key IS NULL)
OR (source = 'imported' AND storage_key IS NOT NULL)
)
);

ALTER TABLE public.broadcast_huds ADD COLUMN IF NOT EXISTS preview text;
ALTER TABLE public.broadcast_huds ADD COLUMN IF NOT EXISTS page_url text;

CREATE INDEX IF NOT EXISTS idx_broadcast_huds_enabled
ON public.broadcast_huds (enabled);

INSERT INTO public.broadcast_huds
(slug, jthud_id, variant, name, description, source)
VALUES
('default-horizontal', 'default', 'horizontal',
'JTs Hud (Horizontal)',
'The layout bundled with JTs Hud Manager, arranged horizontally.',
'builtin'),
('default-vertical', 'default', 'vertical',
'JTs Hud (Vertical)',
'The layout bundled with JTs Hud Manager, arranged vertically.',
'builtin')
ON CONFLICT (slug) DO NOTHING;
5 changes: 5 additions & 0 deletions hasura/triggers/broadcast_huds.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DROP TRIGGER IF EXISTS "set_public_broadcast_huds_updated_at" ON "public"."broadcast_huds";
CREATE TRIGGER "set_public_broadcast_huds_updated_at"
BEFORE UPDATE ON "public"."broadcast_huds"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@nestjs/throttler": "^6.4.0",
"@nestjs/websockets": "^11.1.3",
"@types/uuid": "^11.0.0",
"adm-zip": "^0.6.0",
"archiver": "^7.0.1",
"bullmq": "^5.56.0",
"cache-manager": "^7.0.1",
Expand Down Expand Up @@ -94,6 +95,7 @@
"@nestjs/testing": "^11.1.3",
"@testcontainers/postgresql": "^12.0.4",
"testcontainers": "^12.0.4",
"@types/adm-zip": "^0.5.8",
"@types/archiver": "^6.0.2",
"@types/express": "^5.0.0",
"@types/express-session": "^1.18.0",
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { SanctionsModule } from "./sanctions/sanctions.module";
import { K8sModule } from "./k8s/k8s.module";
import { FileManagerModule } from "./file-manager/file-manager.module";
import { BrandingModule } from "./branding/branding.module";
import { BroadcastHudsModule } from "./broadcast-huds/broadcast-huds.module";
import { AvatarsModule } from "./avatars/avatars.module";
import { AwardsModule } from "./awards/awards.module";
import { FixturesModule } from "./fixtures/fixtures.module";
Expand Down Expand Up @@ -147,6 +148,7 @@ import { UtilityModule } from "./utility/utility.module";
K8sModule,
FileManagerModule,
BrandingModule,
BroadcastHudsModule,
AvatarsModule,
AwardsModule,
FixturesModule,
Expand Down
78 changes: 78 additions & 0 deletions src/broadcast-huds/broadcast-huds.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
BadRequestException,
Body,
Controller,
Delete,
ForbiddenException,
MaxFileSizeValidator,
Param,
ParseFilePipe,
Post,
Req,
UploadedFile,
UseInterceptors,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { Request } from "express";
import { User } from "src/auth/types/User";
import { isRoleAbove } from "src/utilities/isRoleAbove";
import { BroadcastHudsService } from "./broadcast-huds.service";

const MAX_UPLOAD_BYTES = 64 * 1024 * 1024;

@Controller("huds")
export class BroadcastHudsController {
constructor(private readonly huds: BroadcastHudsService) {}

@Post("import")
@UseInterceptors(FileInterceptor("hud"))
public async import(
@Req() request: Request,
@UploadedFile(
new ParseFilePipe({
validators: [new MaxFileSizeValidator({ maxSize: MAX_UPLOAD_BYTES })],
}),
)
file: Express.Multer.File,
) {
this.requireAdmin(request);

if (!file?.buffer?.length) {
throw new BadRequestException("no archive uploaded");
}

const user = request.user as User;
const hud = await this.huds.import(
file.buffer,
file.originalname ?? "hud.zip",
user.steam_id,
);

return { success: true, hud };
}

@Post(":slug/page")
public async setPage(
@Req() request: Request,
@Param("slug") slug: string,
@Body("url") url?: string | null,
) {
this.requireAdmin(request);
const result = await this.huds.setPage(slug, url ?? null);
return { success: true, ...result };
}

@Delete(":slug")
public async remove(@Req() request: Request, @Param("slug") slug: string) {
this.requireAdmin(request);
await this.huds.remove(slug);
return { success: true };
}

private requireAdmin(request: Request) {
const user = request.user as User | undefined;
if (!user || !isRoleAbove(user.role, "administrator")) {
throw new ForbiddenException();
}
}
}
14 changes: 14 additions & 0 deletions src/broadcast-huds/broadcast-huds.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Module } from "@nestjs/common";
import { loggerFactory } from "src/utilities/LoggerFactory";
import { PostgresModule } from "src/postgres/postgres.module";
import { S3Module } from "src/s3/s3.module";
import { BroadcastHudsController } from "./broadcast-huds.controller";
import { BroadcastHudsService } from "./broadcast-huds.service";

@Module({
imports: [PostgresModule, S3Module],
controllers: [BroadcastHudsController],
providers: [BroadcastHudsService, loggerFactory()],
exports: [BroadcastHudsService],
})
export class BroadcastHudsModule {}
Loading