import type { Tables, UserWithPlusTier } from "~/db/tables"; import type * as PlusSuggestionRepository from "~/features/plus-suggestions/PlusSuggestionRepository.server"; import { isAdmin } from "~/modules/permissions/utils"; import { allTruthy } from "~/utils/arrays"; import * as Seasons from "../mmr/core/Seasons"; import { isVotingActive } from "../plus-voting/core"; interface CanAddCommentToSuggestionArgs { user?: Pick; suggestions: PlusSuggestionRepository.FindAllByMonthItem[]; suggested: Pick; targetPlusTier: NonNullable; } export function canAddCommentToSuggestionFE( args: CanAddCommentToSuggestionArgs, ) { return allTruthy([ !alreadyCommentedByUser(args), isPlusServerMember(args.user), args.user?.plusTier && args.targetPlusTier >= args.user?.plusTier, ]); } export function canAddCommentToSuggestionBE({ user, suggestions, suggested, targetPlusTier, }: CanAddCommentToSuggestionArgs) { return allTruthy([ canAddCommentToSuggestionFE({ user, suggestions, suggested, targetPlusTier, }), playerAlreadySuggested({ suggestions, suggested, targetPlusTier }), targetPlusTierIsSmallerOrEqual({ user, targetPlusTier }), ]); } interface CanDeleteCommentArgs { suggestionId: Tables["PlusSuggestion"]["id"]; author: Pick; user?: Pick; suggestions: PlusSuggestionRepository.FindAllByMonthItem[]; } export function canDeleteComment(args: CanDeleteCommentArgs) { const votingActive = process.env.NODE_ENV === "test" ? false : isVotingActive(); if (isFirstSuggestion(args)) { if (votingActive) return false; if (isAdmin(args.user)) return true; return allTruthy([isOwnComment(args), suggestionHasNoOtherComments(args)]); } return isOwnComment(args); } export function isFirstSuggestion({ suggestionId, suggestions, }: Pick) { for (const suggestedUser of Object.values(suggestions).flat()) { for (const [i, entry] of suggestedUser.entries.entries()) { if (entry.id !== suggestionId) continue; return i === 0; } } throw new Error(`Invalid suggestion id: ${suggestionId}`); } function alreadyCommentedByUser({ user, suggestions, suggested, targetPlusTier, }: CanAddCommentToSuggestionArgs) { return suggestions.some( (suggestion) => suggestion.tier === targetPlusTier && suggestion.suggested.id === suggested.id && suggestion.entries.some((entry) => entry.author.id === user?.id), ); } function playerAlreadySuggested({ suggestions, suggested, targetPlusTier, }: Pick< CanAddCommentToSuggestionArgs, "suggestions" | "suggested" | "targetPlusTier" >) { return suggestions.some( (suggestion) => suggestion.suggested.id === suggested.id && suggestion.tier === targetPlusTier, ); } function targetPlusTierIsSmallerOrEqual({ user, targetPlusTier, }: Pick) { return user?.plusTier && user.plusTier <= targetPlusTier; } function isOwnComment({ author, user }: CanDeleteCommentArgs) { return author.id === user?.id; } function suggestionHasNoOtherComments({ suggestions, suggestionId, }: Pick) { for (const suggestedUser of Object.values(suggestions).flat()) { for (const entry of suggestedUser.entries) { if (entry.id !== suggestionId) continue; return suggestedUser.entries.length === 1; } } throw new Error(`Invalid suggestion id: ${suggestionId}`); } interface CanEditSuggestionArgs { suggestionId: Tables["PlusSuggestion"]["id"]; author: Pick; user?: Pick; suggestions: PlusSuggestionRepository.FindAllByMonthItem[]; } export function canEditSuggestion(args: CanEditSuggestionArgs) { const votingActive = process.env.NODE_ENV === "test" ? false : isVotingActive(); return allTruthy([ !votingActive, isFirstSuggestion(args), args.author.id === args.user?.id, ]); } interface CanSuggestNewUserArgs { user?: Pick; suggestions: PlusSuggestionRepository.FindAllByMonthItem[]; } export function canSuggestNewUser({ user, suggestions, }: CanSuggestNewUserArgs) { const votingActive = process.env.NODE_ENV === "test" ? false : isVotingActive(); const existsSeason = Seasons.current() || Seasons.next(); return allTruthy([ !votingActive, !hasUserSuggestedThisMonth({ user, suggestions }), isPlusServerMember(user), existsSeason, ]); } function isPlusServerMember(user?: Pick) { return Boolean(user?.plusTier); } function hasUserSuggestedThisMonth({ user, suggestions, }: Pick) { return suggestions.some( (suggestion) => suggestion.entries[0].author.id === user?.id, ); }