mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-27 04:54:25 -05:00
More progress
This commit is contained in:
@@ -2,22 +2,24 @@ import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { RunningTournaments } from "./RunningTournaments.server";
|
||||
import { testTournament, tournamentCtxTeam } from "./tests/test-utils";
|
||||
|
||||
const createMember = (userId: number) => ({
|
||||
userId,
|
||||
username: `User ${userId}`,
|
||||
discordId: String(userId),
|
||||
discordAvatar: null,
|
||||
customUrl: null,
|
||||
country: null,
|
||||
twitch: null,
|
||||
plusTier: null,
|
||||
createdAt: 0,
|
||||
isOwner: 0,
|
||||
inGameName: null,
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
});
|
||||
const createMember = (userId: number) =>
|
||||
({
|
||||
userId,
|
||||
username: `User ${userId}`,
|
||||
discordId: String(userId),
|
||||
discordAvatar: null,
|
||||
customUrl: null,
|
||||
country: null,
|
||||
twitch: null,
|
||||
plusTier: null,
|
||||
createdAt: 0,
|
||||
isOwner: 0,
|
||||
inGameName: null,
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
}) as const;
|
||||
|
||||
const createTestTournament = (
|
||||
tournamentId: number,
|
||||
|
||||
@@ -827,6 +827,7 @@ export class Tournament {
|
||||
/** Can a new sub post be made at this time? */
|
||||
get canAddNewSubPost() {
|
||||
if (!this.subsFeatureEnabled) return false;
|
||||
if (this.ctx.isFinalized) return false;
|
||||
|
||||
return (
|
||||
!this.ctx.settings.regClosesAt ||
|
||||
|
||||
@@ -49,6 +49,7 @@ describe("tournamentSummary()", () => {
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
})),
|
||||
name: `Team ${teamId}`,
|
||||
prefersNotToHost: 0,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -406,6 +406,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 2899,
|
||||
@@ -422,6 +423,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 6114,
|
||||
@@ -438,6 +440,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33963,
|
||||
@@ -454,6 +457,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 30176,
|
||||
@@ -470,6 +474,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -515,6 +520,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 21689,
|
||||
@@ -531,6 +537,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 3147,
|
||||
@@ -547,6 +554,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 2072,
|
||||
@@ -563,6 +571,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -603,6 +612,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 13370,
|
||||
@@ -619,6 +629,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 45,
|
||||
@@ -635,6 +646,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 1843,
|
||||
@@ -651,6 +663,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -691,6 +704,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 13590,
|
||||
@@ -707,6 +721,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 10757,
|
||||
@@ -723,6 +738,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33047,
|
||||
@@ -739,6 +755,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 41024,
|
||||
@@ -755,6 +772,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -800,6 +818,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 29665,
|
||||
@@ -816,6 +835,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 46006,
|
||||
@@ -832,6 +852,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33483,
|
||||
@@ -848,6 +869,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 11780,
|
||||
@@ -864,6 +886,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 37901,
|
||||
@@ -880,6 +903,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -920,6 +944,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 43662,
|
||||
@@ -936,6 +961,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33491,
|
||||
@@ -952,6 +978,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 46467,
|
||||
@@ -968,6 +995,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 46813,
|
||||
@@ -984,6 +1012,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
@@ -1029,6 +1058,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33611,
|
||||
@@ -1045,6 +1075,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 31148,
|
||||
@@ -1061,6 +1092,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
{
|
||||
userId: 33578,
|
||||
@@ -1077,6 +1109,7 @@ export const ZONES_WEEKLY_38 = (): TournamentData => ({
|
||||
streamTwitch: null,
|
||||
streamViewerCount: null,
|
||||
streamThumbnailUrl: null,
|
||||
role: "REGULAR",
|
||||
},
|
||||
],
|
||||
checkIns: [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -454,34 +454,6 @@ describe("leaveLfg", () => {
|
||||
dbReset();
|
||||
});
|
||||
|
||||
test("removes member from placeholder team", async () => {
|
||||
const tournament = await createTournament();
|
||||
const team = await createPlaceholder(tournament.id, 1);
|
||||
|
||||
await db
|
||||
.insertInto("TournamentTeamMember")
|
||||
.values({
|
||||
tournamentTeamId: team.id,
|
||||
userId: 2,
|
||||
isOwner: 0,
|
||||
role: "REGULAR",
|
||||
})
|
||||
.execute();
|
||||
|
||||
await TournamentLFGRepository.leaveLfg({
|
||||
userId: 2,
|
||||
tournamentId: tournament.id,
|
||||
});
|
||||
|
||||
const groups = await TournamentLFGRepository.findLookingTeamsByTournamentId(
|
||||
tournament.id,
|
||||
);
|
||||
const members = groups[0].members;
|
||||
|
||||
expect(members).toHaveLength(1);
|
||||
expect(members[0].id).toBe(1);
|
||||
});
|
||||
|
||||
test("deletes placeholder team when last member leaves", async () => {
|
||||
const tournament = await createTournament();
|
||||
await createPlaceholder(tournament.id, 1);
|
||||
@@ -498,44 +470,6 @@ describe("leaveLfg", () => {
|
||||
expect(groups).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("promotes MANAGER to OWNER when owner leaves placeholder", async () => {
|
||||
const tournament = await createTournament();
|
||||
const team = await createPlaceholder(tournament.id, 1);
|
||||
|
||||
await db
|
||||
.insertInto("TournamentTeamMember")
|
||||
.values({
|
||||
tournamentTeamId: team.id,
|
||||
userId: 2,
|
||||
isOwner: 0,
|
||||
role: "MANAGER",
|
||||
})
|
||||
.execute();
|
||||
|
||||
await db
|
||||
.insertInto("TournamentTeamMember")
|
||||
.values({
|
||||
tournamentTeamId: team.id,
|
||||
userId: 3,
|
||||
isOwner: 0,
|
||||
role: "REGULAR",
|
||||
})
|
||||
.execute();
|
||||
|
||||
await TournamentLFGRepository.leaveLfg({
|
||||
userId: 1,
|
||||
tournamentId: tournament.id,
|
||||
});
|
||||
|
||||
const groups = await TournamentLFGRepository.findLookingTeamsByTournamentId(
|
||||
tournament.id,
|
||||
);
|
||||
const members = groups[0].members;
|
||||
const newOwner = members.find((m) => m.id === 2);
|
||||
|
||||
expect(newOwner?.role).toBe("OWNER");
|
||||
});
|
||||
|
||||
test("sets isLooking=0 for non-placeholder team", async () => {
|
||||
const tournament = await createTournament();
|
||||
|
||||
|
||||
@@ -163,7 +163,6 @@ export async function findSubGroups(tournamentId: number) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
// xxx: ensure that the team size does not exceed the max, also filter out in frontend
|
||||
export function mergeTeams({
|
||||
survivingTeamId,
|
||||
otherTeamId,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ActionFunctionArgs } from "react-router";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import { requireNotBannedByOrganization } from "~/features/tournament/tournament-utils.server";
|
||||
import {
|
||||
clearTournamentDataCache,
|
||||
tournamentFromDBCached,
|
||||
@@ -15,9 +16,6 @@ import * as TournamentLFGRepository from "../TournamentLFGRepository.server";
|
||||
import { lookingSchema } from "../tournament-lfg-schemas";
|
||||
import { survivingTeamId } from "../tournament-lfg-utils";
|
||||
|
||||
// xxx: prevent actions in certain cases? like when tournament has started
|
||||
// xxx: add `requireNotBannedByOrganization` & other checks from deleted to.$id.subs.new.tsx route
|
||||
|
||||
export const action = async ({ request, params }: ActionFunctionArgs) => {
|
||||
const user = requireUser();
|
||||
const { id: tournamentId } = parseParams({ params, schema: idObject });
|
||||
@@ -53,14 +51,20 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
|
||||
tournamentId,
|
||||
user,
|
||||
});
|
||||
await requireNotBannedByOrganization({ tournament, user });
|
||||
errorToastIfFalsy(
|
||||
tournament.canAddNewSubPost,
|
||||
"Cannot add sub post at this time",
|
||||
);
|
||||
const team = tournament.teamMemberOfByUser(user);
|
||||
|
||||
if (team) {
|
||||
// xxx: or isManager, also just show errorToast no return null
|
||||
const isTeamOwner = team.members.some(
|
||||
(m) => m.userId === user.id && m.isOwner,
|
||||
const member = team.members.find((m) => m.userId === user.id);
|
||||
const canManageTeam = member?.isOwner || member?.role === "MANAGER";
|
||||
errorToastIfFalsy(
|
||||
canManageTeam,
|
||||
"Only team owners and managers can join the queue",
|
||||
);
|
||||
if (!isTeamOwner) return null;
|
||||
|
||||
errorToastIfFalsy(
|
||||
team.members.length < tournament.maxMembersPerTeam,
|
||||
@@ -210,6 +214,8 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
|
||||
tournamentId,
|
||||
user,
|
||||
});
|
||||
await requireNotBannedByOrganization({ tournament, user });
|
||||
errorToastIfFalsy(!tournament.everyBracketOver, "Tournament is over");
|
||||
errorToastIfFalsy(
|
||||
tournament.canAddNewSubPost,
|
||||
"Cannot add sub post at this time",
|
||||
|
||||
@@ -152,7 +152,7 @@ async function resolveOwnTeam({
|
||||
languages: [],
|
||||
vc: null,
|
||||
pronouns: null,
|
||||
role: m.isOwner ? "OWNER" : "REGULAR",
|
||||
role: m.isOwner ? "OWNER" : m.role === "MANAGER" ? "MANAGER" : "REGULAR",
|
||||
isStayAsSub: false,
|
||||
weapons: null,
|
||||
plusTier: m.plusTier,
|
||||
|
||||
@@ -53,8 +53,6 @@ export default function TournamentLFGShell() {
|
||||
return <TournamentLFGPage />;
|
||||
}
|
||||
|
||||
// xxx: no button if already in the tournament
|
||||
// xxx: can we reuse the column layout with sendouq?
|
||||
function TournamentLFGPage() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
if (data.mode === "subs") {
|
||||
|
||||
@@ -178,6 +178,7 @@ export async function findById(id: number) {
|
||||
"SeedingSkill.ordinal",
|
||||
"PlusTier.tier as plusTier",
|
||||
"TournamentTeamMember.isOwner",
|
||||
"TournamentTeamMember.role",
|
||||
"TournamentTeamMember.createdAt",
|
||||
sql<string | null> /*sql*/`coalesce(
|
||||
"TournamentTeamMember"."inGameName",
|
||||
|
||||
Reference in New Issue
Block a user