From 4b879cb299b70b1ab9a79d96a9cf952ca6a5afad Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 13:46:19 -0400 Subject: [PATCH 001/153] Some more work on new GQL stuff --- new-desing.graphql | 516 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 new-desing.graphql diff --git a/new-desing.graphql b/new-desing.graphql new file mode 100644 index 00000000..bbd55218 --- /dev/null +++ b/new-desing.graphql @@ -0,0 +1,516 @@ +# Custom Scalars + +""" +A cursor for use in paginating through collections of data. Cursors are opaque strings that are +intended to be used by clients to paginate through a connection. Clients should not attempt to +destructure or parse the cursor string, as the format may change at any time. +""" +scalar Cursor + +""" +This is a special scalar that is used to represent the unique identifier of a node. It is serialized +as a string and parsed from a string. It is guaranteed to be unique across all nodes in the system, +and is used to identify nodes in the Relay specification. For the purposes of this schema, it is +an opaque string that can be used to identify a node. The client should never attempt to parse or +destructure this value, as the format may change at any time. +""" +scalar NodeID + +# GraphQL Scalars + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates +and times using the Gregorian calendar.This scalar is serialized to a string in ISO 8601 format and +parsed from a string in ISO 8601 format. +""" +scalar DateTimeISO + +""" +A string representing a duration conforming to the ISO8601 standard, such as P1W1DT13H23M34S. +""" +scalar Duration + +""" +A field whose value conforms to the standard internet email address format as specified in HTML +Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. +""" +scalar EmailAddress + @specifiedBy( + url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address" + ) + +""" +Integers that will have a value of 0 or more. +""" +scalar NonNegativeInt + +""" +Integers that will have a value greater than 0. +""" +scalar PositiveInt + +""" +A field whose value conforms to the standard URL format as specified in RFC3986: https://www.ietf.org/rfc/rfc3986.txt. +""" +scalar URL + +""" +Represents NULL values +""" +scalar Void + +scalar UUID + +# Enums + +""" +The source of authentication +""" +enum AuthSource { + Anonymous + Demo + LinkBlue + None +} + +""" +The identifier for a committee +""" +enum CommitteeIdentifier { + communityDevelopmentCommittee + corporateCommittee + dancerRelationsCommittee + familyRelationsCommittee + fundraisingCommittee + marketingCommittee + miniMarathonsCommittee + operationsCommittee + programmingCommittee + techCommittee + viceCommittee +} + +""" +Roles within a committee +""" +enum CommitteeRole { + Chair + Coordinator + Member +} + +""" +DanceBlue roles +""" +enum DbRole { + Committee + None + Public + UKY +} + +""" +The position of a member on a team +""" +enum MembershipPositionType { + Captain + Member +} + +enum SortDirection { + ASCENDING + DESCENDING +} + +""" +New Team vs Returning Team +""" +enum TeamLegacyStatus { + DemoTeam + NewTeam + ReturningTeam +} + +""" +Types of teams +""" +enum PointType { + Morale + Spirit +} + +enum ErrorCode { + INTERNAL_ERROR +} + +# Re-used Types + +type PageInfo { + """ + hasPreviousPage is used to indicate whether more edges exist prior to the set defined by the + clients arguments. If the client is paginating with last/before, then the server must return + true if prior edges exist, otherwise false. If the client is paginating with first/after, + then the client may return true if edges prior to after exist, if it can do so efficiently, + otherwise may return false. + """ + hasPreviousPage: Boolean! + """ + hasNextPage is used to indicate whether more edges exist following the set defined by the clients + arguments. If the client is paginating with first/after, then the server must return true if + further edges exist, otherwise false. If the client is paginating with last/before, then the + client may return true if edges further from before exist, if it can do so efficiently, otherwise + may return false. + """ + hasNextPage: Boolean! + """ + startCursor is simply an opaque value that refers to the first position in a connection. It is + used by the client to request the first set of edges in a connection. The server must return + the cursor that corresponds to the first element in the connection. + """ + startCursor: Cursor + """ + endCursor is simply an opaque value that refers to the last position in a connection. It is + used by the client to request the last set of edges in a connection. The server must return + the cursor that corresponds to the last element in the connection. + """ + endCursor: Cursor +} + +type Error { + """ + A specific error code to identify the error + """ + code: ErrorCode! + """ + A human readable error message + """ + message: String! + """ + A message that should be presented to the user + """ + alert: String + """ + Development information about the error. should not be sent to untrusted clients (i.e. production environments) + """ + debugInfo: String +} + +type IntervalISO { + """ + The beginning of the interval + """ + start: DateTimeISO! + """ + The end of the interval + """ + end: DateTimeISO! + + """ + The ISO formatted interval + """ + iso8601: String + + """ + The duration of the interval + """ + duration: Duration + + """ + Whether the interval is empty, meaning the start and end are the same + """ + isEmpty: Boolean +} + +# Interfaces + +interface Node { + id: NodeID! +} + +interface Edge { + cursor: Cursor! + node: Node! +} + +interface Errorable { + errors: [Error!]! +} + +interface Connection implements Errorable { + totalCount: NonNegativeInt! + edges: [Edge!]! + pageInfo: PageInfo! + errors: [Error!]! +} + +interface Resource implements Errorable { + node: Node! + errors: [Error!]! +} + +interface Result implements Errorable { + node: Node + errors: [Error!]! +} + +# Resources + +type Configuration { + uuid: UUID! + createdAt: DateTimeISO + key: String! + updatedAt: DateTimeISO + validAfter: DateTimeISO + validUntil: DateTimeISO + value: String! +} + +type Device { + uuid: UUID! + createdAt: DateTimeISO + expoPushToken: String + lastLoggedInUser: Person + lastLogin: DateTimeISO + notificationDeliveries( + page: PositiveInt = 1 + pageSize: NonNegativeInt = 10 + ): [NotificationDelivery!]! + updatedAt: DateTimeISO +} + +type Event { + uuid: UUID! + + title: String! + summary: String + description: String + images: [Image!]! + location: String + occurrences: [IntervalISO!]! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Feed { + uuid: UUID! + + title: String! + image: Image + textContent: String + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Image { + uuid: UUID! + + url: URL + alt: String + mimeType: String! + thumbHash: String + height: NonNegativeInt! + width: NonNegativeInt! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type MarathonHour { + uuid: UUID! + + title: String! + details: String + durationInfo: String! + + shownStartingAt: DateTimeISO! + + createdAt: DateTimeISO + updatedAt: DateTimeISO +} + +type Marathon { + uuid: UUID! + + hours: [MarathonHour!]! + + interval: IntervalISO! + + updatedAt: DateTimeISO + createdAt: DateTimeISO + + """ + A four digit year + """ + year: String! +} + +type Membership { + uuid: UUID! + + person: Person! + team: Team! + + position: MembershipPositionType! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type NotificationDelivery { + uuid: UUID! + + notification: Notification! + + """ + A unique identifier corresponding the group of notifications this was sent to Expo with. + """ + chunkUuid: String + + """ + Any error message returned by Expo when sending the notification. + """ + deliveryError: String + + """ + The time the server received a delivery receipt from the user. + """ + receiptCheckedAt: DateTimeISO + + """ + The time the server sent the notification to Expo for delivery. + """ + sentAt: DateTimeISO + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Notification { + uuid: UUID! + + title: String! + body: String! + + """ + The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. + """ + sendAt: DateTimeISO + + """ + The time the server started sending the notification. + """ + startedSendingAt: DateTimeISO + url: URL + + deliveryCount: NonNegativeInt! + deliveryIssue: String + deliveryIssueAcknowledgedAt: DateTimeISO + deliveryIssueCount: NonNegativeInt! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Person { + uuid: UUID! + + role: Role! + teams: [Membership!]! + + email: String! + linkblue: String + name: String + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type PointEntry { + uuid: UUID! + + personFrom: Person + team: Team! + + comment: String + pointOpportunity: PointOpportunity + points: NonNegativeInt! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type PointOpportunity { + uuid: UUID! + + event: Event + + name: String! + opportunityDate: DateTimeISO + type: PointType! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Role { + committeeIdentifier: CommitteeIdentifier + committeeRole: CommitteeRole + dbRole: DbRole! +} + +type Team { + uuid: UUID! + + members: [Membership!]! + pointEntries: [PointEntry!]! + + legacyStatus: TeamLegacyStatus! + type: PointType! + name: String! + totalPoints: NonNegativeInt! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type Committee { + uuid: UUID! + + team: Team! + + parentCommittee: Committee + subCommittees: [Committee!]! + + committeeIdentifier: CommitteeIdentifier! + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +# Input types for mutations + +# Output types for mutations + +# Connection types + +# Output types for queries + +# Root types + +type Query { + me: Person + + node( + """ + The ID of the node to retrieve + """ + id: NodeID! + ): Node +} + +type Mutation { + +} From 808494ca9a6bdaf8b0c86bbcc466128238894587 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 18:35:54 +0000 Subject: [PATCH 002/153] Update GraphQL schema with new types and fields --- .vscode/settings.json | 2 +- new-desing.graphql | 178 ++++++++++++++++++++++++++++-------------- 2 files changed, 121 insertions(+), 59 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e8cbed29..7c5dc216 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,6 @@ "typescript.inlayHints.parameterNames.enabled": "all", "typescript.preferences.preferTypeOnlyAutoImports": true, "javascript.inlayHints.parameterNames.enabled": "all", - "cSpell.words": ["cooldown", "Spinnable", "Whatwg"], + "cSpell.words": ["cooldown", "Leaderboards", "Spinnable", "Whatwg"], "eslint.codeActionsOnSave.mode": "problems" } diff --git a/new-desing.graphql b/new-desing.graphql index bbd55218..853adb8b 100644 --- a/new-desing.graphql +++ b/new-desing.graphql @@ -74,23 +74,6 @@ enum AuthSource { None } -""" -The identifier for a committee -""" -enum CommitteeIdentifier { - communityDevelopmentCommittee - corporateCommittee - dancerRelationsCommittee - familyRelationsCommittee - fundraisingCommittee - marketingCommittee - miniMarathonsCommittee - operationsCommittee - programmingCommittee - techCommittee - viceCommittee -} - """ Roles within a committee """ @@ -144,6 +127,19 @@ enum ErrorCode { INTERNAL_ERROR } +""" +All the tabs the app can show +""" +enum MobileAppTab { + Home + Events + Explore + Teams + Marathon + DBMoments + Info +} + # Re-used Types type PageInfo { @@ -258,24 +254,35 @@ interface Result implements Errorable { type Configuration { uuid: UUID! - createdAt: DateTimeISO + key: String! - updatedAt: DateTimeISO + value: String! validAfter: DateTimeISO validUntil: DateTimeISO - value: String! + + setBy: Person + + updatedAt: DateTimeISO + createdAt: DateTimeISO +} + +type MobileAppConfiguration { + shownTabs: [MobileAppTab!]! + fancyTab: MobileAppTab + allowedLoginTypes: [AuthSource!]! } type Device { uuid: UUID! - createdAt: DateTimeISO - expoPushToken: String + lastLoggedInUser: Person lastLogin: DateTimeISO notificationDeliveries( page: PositiveInt = 1 pageSize: NonNegativeInt = 10 ): [NotificationDelivery!]! + + createdAt: DateTimeISO updatedAt: DateTimeISO } @@ -289,7 +296,9 @@ type Event { location: String occurrences: [IntervalISO!]! + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } @@ -300,7 +309,9 @@ type Feed { image: Image textContent: String + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } @@ -314,10 +325,37 @@ type Image { height: NonNegativeInt! width: NonNegativeInt! + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } +""" +Describes a set of teams whose points are compared +""" +type Leaderboard { + uuid: UUID! + + """ + An ordered list of teams + """ + teams: [Team!]! + + # The filters applied to this leaderboard + legacyStatus: TeamLegacyStatus + """ + If true: only committee teams are included, if false: only non-committee teams are included, if null: all teams are included + """ + committee: Boolean + pointType: PointType! + + """ + A short user-friendly description of the leaderboard + """ + description: String +} + type MarathonHour { uuid: UUID! @@ -327,7 +365,9 @@ type MarathonHour { shownStartingAt: DateTimeISO! + updatedBy: Person createdAt: DateTimeISO + createdBy: Person updatedAt: DateTimeISO } @@ -336,15 +376,38 @@ type Marathon { hours: [MarathonHour!]! - interval: IntervalISO! - - updatedAt: DateTimeISO - createdAt: DateTimeISO - """ A four digit year """ year: String! + interval: IntervalISO! + + allSpiritTeamsLeaderboard: Leaderboard! + returningSpiritTeamsLeaderboard: Leaderboard! + newSpiritTeamsLeaderboard: Leaderboard! + committeeSpiritTeamsLeaderboard: Leaderboard! + nonCommitteeSpiritTeamsLeaderboard: Leaderboard! + moraleLeaderboard: Leaderboard! + + communityDevelopmentCommittee: Committee! + corporateCommittee: Committee! + dancerRelationsCommittee: Committee! + familyRelationsCommittee: Committee! + fundraisingCommittee: Committee! + marketingCommittee: Committee! + miniMarathonsCommittee: Committee! + operationsCommittee: Committee! + programmingCommittee: Committee! + techCommittee: Committee! + viceCommittee: Committee! + overallCommittee: Committee! + + teams: [Team!]! + + updatedBy: Person + createdAt: DateTimeISO + createdBy: Person + updatedAt: DateTimeISO } type Membership { @@ -355,8 +418,10 @@ type Membership { position: MembershipPositionType! - updatedAt: DateTimeISO + updatedBy: Person createdAt: DateTimeISO + createdBy: Person + updatedAt: DateTimeISO } type NotificationDelivery { @@ -394,6 +459,7 @@ type Notification { title: String! body: String! + sentBy: Person """ The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. """ @@ -410,8 +476,10 @@ type Notification { deliveryIssueAcknowledgedAt: DateTimeISO deliveryIssueCount: NonNegativeInt! - updatedAt: DateTimeISO + updatedBy: Person createdAt: DateTimeISO + createdBy: Person + updatedAt: DateTimeISO } type Person { @@ -419,12 +487,16 @@ type Person { role: Role! teams: [Membership!]! + primaryCommittee: Committee + committees: [Committee!]! + name: String email: String! linkblue: String - name: String + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } @@ -438,7 +510,9 @@ type PointEntry { pointOpportunity: PointOpportunity points: NonNegativeInt! + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } @@ -447,16 +521,20 @@ type PointOpportunity { event: Event + marathon: Marathon! + name: String! opportunityDate: DateTimeISO type: PointType! + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } type Role { - committeeIdentifier: CommitteeIdentifier + committee: Committee committeeRole: CommitteeRole dbRole: DbRole! } @@ -467,12 +545,16 @@ type Team { members: [Membership!]! pointEntries: [PointEntry!]! + marathon: Marathon! + legacyStatus: TeamLegacyStatus! type: PointType! name: String! totalPoints: NonNegativeInt! + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } @@ -481,36 +563,16 @@ type Committee { team: Team! + chairs: [Person!]! + coordinators: [Person!]! + members: [Person!]! + allMembers: [Person!]! + parentCommittee: Committee subCommittees: [Committee!]! - committeeIdentifier: CommitteeIdentifier! - + updatedBy: Person updatedAt: DateTimeISO + createdBy: Person createdAt: DateTimeISO } - -# Input types for mutations - -# Output types for mutations - -# Connection types - -# Output types for queries - -# Root types - -type Query { - me: Person - - node( - """ - The ID of the node to retrieve - """ - id: NodeID! - ): Node -} - -type Mutation { - -} From a2bf5e07e49e4fd362071cb60b73d0b093de2af6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 18:41:58 +0000 Subject: [PATCH 003/153] Add custom scalar types for NodeID and Cursor --- packages/common/lib/api/scalars/Cursor.ts | 27 ++++++ .../common/lib/api/scalars/DateRangeScalar.ts | 85 ------------------- .../common/lib/api/scalars/DateTimeScalar.ts | 58 ------------- .../common/lib/api/scalars/DurationScalar.ts | 56 ------------ packages/common/lib/api/scalars/NodeID.ts | 23 +++++ 5 files changed, 50 insertions(+), 199 deletions(-) create mode 100644 packages/common/lib/api/scalars/Cursor.ts delete mode 100644 packages/common/lib/api/scalars/DateRangeScalar.ts delete mode 100644 packages/common/lib/api/scalars/DateTimeScalar.ts delete mode 100644 packages/common/lib/api/scalars/DurationScalar.ts create mode 100644 packages/common/lib/api/scalars/NodeID.ts diff --git a/packages/common/lib/api/scalars/Cursor.ts b/packages/common/lib/api/scalars/Cursor.ts new file mode 100644 index 00000000..be6e04e2 --- /dev/null +++ b/packages/common/lib/api/scalars/Cursor.ts @@ -0,0 +1,27 @@ +import { GraphQLScalarType, Kind } from "graphql"; + +export const CursorScalar = new GraphQLScalarType({ + name: "Cursor", + description: "Cursor custom scalar type", + parseValue(value): string { + if (typeof value === "string") { + return value; + } else { + throw new TypeError("CursorScalar can only parse strings"); + } + }, + serialize(value): string { + if (typeof value === "string") { + return value; + } else { + throw new TypeError("CursorScalar can only serialize strings"); + } + }, + parseLiteral(ast): string { + if (ast.kind === Kind.STRING) { + return ast.value; + } else { + throw new TypeError("CursorScalar can only parse literal string values"); + } + }, +}); diff --git a/packages/common/lib/api/scalars/DateRangeScalar.ts b/packages/common/lib/api/scalars/DateRangeScalar.ts deleted file mode 100644 index c6a7a2d4..00000000 --- a/packages/common/lib/api/scalars/DateRangeScalar.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { GraphQLScalarType, Kind } from "graphql"; -import { DateTime, Duration, Interval } from "luxon"; - -import { LuxonError } from "../../utility/errors/validation.js"; - -export const DateRangeScalar = new GraphQLScalarType({ - name: "LuxonDateRange", - description: "Date range custom scalar type (just an ISO 8601 interval)", - parseValue(value): Interval { - if (value == null) { - throw new TypeError("DateRangeScalar cannot parse nullish values"); - } - if (typeof value === "string") { - const interval = Interval.fromISO(value); - if (!interval.isValid) { - throw new LuxonError(interval); - } - return interval; - } - if (Interval.isInterval(value)) { - return value; - } - if (Array.isArray(value) && value.length === 2) { - if (DateTime.isDateTime(value[0])) { - if (DateTime.isDateTime(value[1])) { - return Interval.fromDateTimes(value[0], value[1]); - } - if (Duration.isDuration(value[1])) { - return Interval.after(value[0], value[1]); - } - } - if (value[0] instanceof Date && value[1] instanceof Date) { - if ( - value[0].toString() === "Invalid Date" || - value[1].toString() === "Invalid Date" - ) { - throw new TypeError( - "DateRangeScalar cannot parse tuples of [Date, Date] with invalid dates" - ); - } - return Interval.fromDateTimes( - DateTime.fromJSDate(value[0]), - DateTime.fromJSDate(value[1]) - ); - } - throw new TypeError( - "DateRangeScalar can only parse tuples of [DateTime, DateTime], [Date, Date] or [DateTime, Duration]" - ); - } - throw new TypeError( - "DateRangeScalar can only parse strings, Luxon intervals, or tuples of [DateTime, DateTime], [Date, Date] or [DateTime, Duration]" - ); - }, - parseLiteral(ast): Interval { - if (ast.kind === Kind.STRING) { - const interval = Interval.fromISO(ast.value); - if (!interval.isValid) { - throw new LuxonError(interval); - } - return interval; - } - throw new TypeError("DateRangeScalar can only parse literal string values"); - }, - specifiedByURL: "https://www.iso.org/iso-8601-date-and-time-format.html", - serialize(value): string { - if (Interval.isInterval(value) && value.isValid) { - return value.toISO(); - } else if (typeof value === "string") { - const interval = Interval.fromISO(value); - if (interval.isValid) { - return interval.toISO(); - } else { - throw new TypeError( - "DateRangeScalar can only serialize strings that are valid ISO 8601 intervals", - { - cause: new LuxonError(interval), - } - ); - } - } - throw new TypeError( - "DateRangeScalar can only serialize Luxon Interval objects" - ); - }, -}); diff --git a/packages/common/lib/api/scalars/DateTimeScalar.ts b/packages/common/lib/api/scalars/DateTimeScalar.ts deleted file mode 100644 index 68b23407..00000000 --- a/packages/common/lib/api/scalars/DateTimeScalar.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { GraphQLScalarType, Kind } from "graphql"; -import { DateTime } from "luxon"; - -export const DateTimeScalar = new GraphQLScalarType({ - name: "LuxonDateTime", - description: "Luxon DateTime custom scalar type", - parseValue(value): DateTime { - if (typeof value === "string") { - return DateTime.fromISO(value); - } else if (DateTime.isDateTime(value)) { - return value; - } else if (typeof value === "number") { - return DateTime.fromMillis(value); - } else if (value instanceof Date) { - return DateTime.fromJSDate(value); - } else if (value && typeof value === "object") { - const dateTimeFromObject = DateTime.fromObject(value); - if (dateTimeFromObject.isValid) { - return dateTimeFromObject; - } else { - throw new TypeError( - "DateTimeScalar can only parse objects that are valid Luxon DateTime objects" - ); - } - } else { - throw new TypeError( - "DateTimeScalar can only parse strings, numbers, Date objects, or Luxon DateTime objects" - ); - } - }, - serialize(value): string { - if (typeof value === "string") { - const dateTime = DateTime.fromISO(value); - if (dateTime.isValid) { - return dateTime.toISO(); - } else { - throw new TypeError( - "DateTimeScalar can only serialize strings that are valid ISO 8601 dates" - ); - } - } else if (DateTime.isDateTime(value) && value.isValid) { - return value.toISO(); - } else { - throw new TypeError( - "DateTimeScalar can only serialize strings or Luxon DateTime objects" - ); - } - }, - parseLiteral(ast): DateTime { - if (ast.kind === Kind.STRING) { - return DateTime.fromISO(ast.value); - } else { - throw new TypeError( - "DateTimeScalar can only parse literal string values" - ); - } - }, -}); diff --git a/packages/common/lib/api/scalars/DurationScalar.ts b/packages/common/lib/api/scalars/DurationScalar.ts deleted file mode 100644 index 4697aa74..00000000 --- a/packages/common/lib/api/scalars/DurationScalar.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { GraphQLScalarType, Kind } from "graphql"; -import { Duration } from "luxon"; - -export const DurationScalar = new GraphQLScalarType({ - name: "LuxonDuration", - description: "Luxon Duration custom scalar type", - parseValue(value): Duration { - if (typeof value === "string") { - return Duration.fromISO(value); - } else if (Duration.isDuration(value)) { - return value; - } else if (typeof value === "number") { - return Duration.fromMillis(value); - } else if (value && typeof value === "object") { - const durationFromObject = Duration.fromObject(value); - if (durationFromObject.isValid as boolean) { - return durationFromObject; - } else { - throw new TypeError( - "DurationScalar can only parse objects that are valid Luxon Duration objects" - ); - } - } else { - throw new TypeError( - "DurationScalar can only parse strings, numbers, or Luxon Duration objects" - ); - } - }, - serialize(value): string { - if (typeof value === "string") { - const duration = Duration.fromISO(value); - if (duration.isValid) { - return duration.toISO(); - } else { - throw new TypeError( - "DurationScalar can only serialize strings that are valid ISO 8601 durations" - ); - } - } else if (Duration.isDuration(value) && value.isValid) { - return value.toISO(); - } else { - throw new TypeError( - "DurationScalar can only serialize strings or Luxon Duration objects" - ); - } - }, - parseLiteral(ast): Duration { - if (ast.kind === Kind.STRING) { - return Duration.fromISO(ast.value); - } else { - throw new TypeError( - "DurationScalar can only parse literal string values" - ); - } - }, -}); diff --git a/packages/common/lib/api/scalars/NodeID.ts b/packages/common/lib/api/scalars/NodeID.ts new file mode 100644 index 00000000..18906eb3 --- /dev/null +++ b/packages/common/lib/api/scalars/NodeID.ts @@ -0,0 +1,23 @@ +import { GraphQLScalarType } from "graphql"; + +export const NodeIDScalar = new GraphQLScalarType({ + name: "NodeID", + description: "Node ID custom scalar type", + parseValue(value): string { + if (typeof value === "string") { + return value; + } else { + throw new TypeError("NodeIDScalar can only parse strings"); + } + }, + serialize(value): string { + if (typeof value === "string") { + return value; + } else { + throw new TypeError("NodeIDScalar can only serialize strings"); + } + }, + parseLiteral(): string { + throw new TypeError("NodeIDScalar should never be used in literal form"); + }, +}); From 2de4dc65f8bab3613c3ad8c91770c6714a627246 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 20:46:11 +0000 Subject: [PATCH 004/153] Import DateTimeISOResolver from graphql-scalars --- .../common/lib/api/resources/Configuration.ts | 7 ++--- packages/common/lib/api/resources/Device.ts | 5 ++-- .../lib/api/resources/LoginFlowSession.ts | 29 ------------------- packages/common/lib/api/resources/index.ts | 1 - 4 files changed, 5 insertions(+), 37 deletions(-) delete mode 100644 packages/common/lib/api/resources/LoginFlowSession.ts diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index 265bebf2..c5014686 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -1,8 +1,7 @@ +import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; -import { DateTimeScalar } from "../scalars/DateTimeScalar.js"; - import { TimestampedResource } from "./Resource.js"; /* @@ -27,10 +26,10 @@ export class ConfigurationResource extends TimestampedResource { @Field(() => String) value!: string; - @Field(() => DateTimeScalar, { nullable: true }) + @Field(() => DateTimeISOResolver, { nullable: true }) validAfter!: DateTime | null; - @Field(() => DateTimeScalar, { nullable: true }) + @Field(() => DateTimeISOResolver, { nullable: true }) validUntil!: DateTime | null; public getUniqueId(): string { diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index f9327115..5df5485a 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -1,8 +1,7 @@ +import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; -import { DateTimeScalar } from "../scalars/DateTimeScalar.js"; - import { TimestampedResource } from "./Resource.js"; @ObjectType() @@ -11,7 +10,7 @@ export class DeviceResource extends TimestampedResource { uuid!: string; @Field(() => String, { nullable: true }) public expoPushToken!: string | null; - @Field(() => DateTimeScalar, { nullable: true }) + @Field(() => DateTimeISOResolver, { nullable: true }) public lastLogin!: DateTime | null; public getUniqueId(): string { diff --git a/packages/common/lib/api/resources/LoginFlowSession.ts b/packages/common/lib/api/resources/LoginFlowSession.ts deleted file mode 100644 index 4345aab7..00000000 --- a/packages/common/lib/api/resources/LoginFlowSession.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { URLResolver } from "graphql-scalars"; -import { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; - -import { DateTimeScalar } from "../scalars/DateTimeScalar.js"; - -import { TimestampedResource } from "./Resource.js"; - -// TODO: Maybe remove - -@ObjectType() -export class LoginFlowSessionResource extends TimestampedResource { - @Field(() => ID) - uuid!: string; - @Field(() => String) - codeVerifier!: string; - @Field(() => DateTimeScalar) - creationDate!: DateTime; - @Field(() => URLResolver, { nullable: true }) - redirectToAfterLogin!: URL | null; - - public getUniqueId(): string { - return this.uuid; - } - - public static init(init: Partial) { - return LoginFlowSessionResource.doInit(init); - } -} diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index ced6bad1..b802912d 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -4,7 +4,6 @@ export { DeviceResource } from "./Device.js"; export { EventOccurrenceResource, EventResource } from "./Event.js"; export { FeedResource } from "./FeedResource.js"; export { ImageResource } from "./Image.js"; -export { LoginFlowSessionResource } from "./LoginFlowSession.js"; export * from "./Marathon.js"; export * from "./MarathonHour.js"; export { MembershipPositionType, MembershipResource } from "./Membership.js"; From d63102682a1ba679af6f765393dfb646c3612cd5 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 20:46:16 +0000 Subject: [PATCH 005/153] Add Node, Edge, Connection, Resource, Result, PageInfo, and ResourceError classes --- packages/common/lib/api/relay.ts | 83 ++++++++++++++++++++++++ packages/common/lib/api/resourceError.ts | 46 +++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 packages/common/lib/api/relay.ts create mode 100644 packages/common/lib/api/resourceError.ts diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts new file mode 100644 index 00000000..40879889 --- /dev/null +++ b/packages/common/lib/api/relay.ts @@ -0,0 +1,83 @@ +import { Field, InterfaceType, ObjectType } from "type-graphql"; + +import { Errorable, ResourceError } from "./resourceError.js"; +import { CursorScalar } from "./scalars/Cursor.js"; +import { NodeIDScalar } from "./scalars/NodeID.js"; + +@InterfaceType() +export class Node { + @Field(() => NodeIDScalar) + id!: string; +} +@InterfaceType() +export class Edge { + @Field(() => CursorScalar) + cursor!: string; + + @Field(() => Node) + node!: string; +} + +@InterfaceType({ implements: [Errorable] }) +export class Connection implements Errorable { + @Field(() => Number, { name: "totalCount" }) + totalCount!: number; + + @Field(() => [Edge], { name: "edges" }) + edges!: Edge[]; + + @Field(() => PageInfo, { name: "pageInfo" }) + pageInfo!: PageInfo; + + @Field(() => [ResourceError], { name: "errors" }) + errors!: ResourceError[]; +} + +@InterfaceType({ implements: [Errorable] }) +export class Resource implements Errorable { + @Field(() => Node, { name: "node" }) + node!: Node; + + @Field(() => [ResourceError], { name: "errors" }) + errors!: ResourceError[]; +} + +@InterfaceType({ implements: [Errorable] }) +export class Result implements Errorable { + @Field(() => Node, { name: "node" }) + node!: Node; + + @Field(() => [ResourceError], { name: "errors" }) + errors!: ResourceError[]; +} + +@ObjectType() +export class PageInfo { + @Field(() => Boolean, { + name: "hasPreviousPage", + description: + "hasPreviousPage is used to indicate whether more edges exist prior to the set defined by the clients arguments. If the client is paginating with last/before, then the server must return true if prior edges exist, otherwise false. If the client is paginating with first/after, then the client may return true if edges prior to after exist, if it can do so efficiently, otherwise may return false.", + }) + hasPreviousPage!: boolean; + + @Field(() => Boolean, { + name: "hasNextPage", + description: + "hasNextPage is used to indicate whether more edges exist following the set defined by the clients arguments. If the client is paginating with first/after, then the server must return true if further edges exist, otherwise false. If the client is paginating with last/before, then the client may return true if edges further from before exist, if it can do so efficiently, otherwise may return false.", + }) + hasNextPage!: boolean; + + @Field(() => CursorScalar, { + name: "startCursor", + description: + "startCursor is simply an opaque value that refers to the first position in a connection. It is used by the client to request the first set of edges in a connection. The server must return the cursor that corresponds to the first element in the connection.", + }) + startCursor!: string; + + @Field(() => CursorScalar, { + name: "endCursor", + description: + "endCursor is simply an opaque value that refers to the last position in a connection. It is used by the client to request the last set of edges in a connection. The server must return the cursor that corresponds to the last element in the connection.", + }) + endCursor!: string; +} diff --git a/packages/common/lib/api/resourceError.ts b/packages/common/lib/api/resourceError.ts new file mode 100644 index 00000000..971a7ec8 --- /dev/null +++ b/packages/common/lib/api/resourceError.ts @@ -0,0 +1,46 @@ +import { + Field, + InterfaceType, + ObjectType, + registerEnumType, +} from "type-graphql"; + +export const ResourceErrorCode = { + InternalError: "InternalError", +} as const; +export type ResourceErrorCode = + (typeof ResourceErrorCode)[keyof typeof ResourceErrorCode]; + +registerEnumType(ResourceErrorCode, { + name: "ResourceErrorCode", +}); + +@ObjectType("ResourceError") +export class ResourceError { + @Field(() => ResourceErrorCode, { + description: "A specific error code to identify the error", + }) + code!: ResourceErrorCode; + + @Field(() => String, { description: "A human readable error message" }) + message!: string; + + @Field(() => String, { + nullable: true, + description: "A message that should be presented to the user", + }) + alert?: string; + + @Field(() => String, { + nullable: true, + description: + "Development information about the error. should not be sent to untrusted clients (i.e. production environments)", + }) + debugInfo?: string; +} + +@InterfaceType() +export abstract class Errorable { + @Field(() => [ResourceError]) + errors!: ResourceError[]; +} From d543196bbd19ddf8e65e9e575fbb403051b453a6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 20 Apr 2024 20:46:22 +0000 Subject: [PATCH 006/153] Update cSpell.words in .vscode/settings.json --- .vscode/settings.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7c5dc216..07a4092f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,12 @@ "typescript.inlayHints.parameterNames.enabled": "all", "typescript.preferences.preferTypeOnlyAutoImports": true, "javascript.inlayHints.parameterNames.enabled": "all", - "cSpell.words": ["cooldown", "Leaderboards", "Spinnable", "Whatwg"], + "cSpell.words": [ + "cooldown", + "Errorable", + "Leaderboards", + "Spinnable", + "Whatwg" + ], "eslint.codeActionsOnSave.mode": "problems" } From 9c6db1215ee25202912424d7492d93defabaa863 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 03:58:17 +0000 Subject: [PATCH 007/153] Update id and tweak relay defs --- packages/common/lib/api/relay.ts | 61 ++++++++++++++----- .../common/lib/api/resources/Configuration.ts | 12 +++- packages/common/lib/api/resources/Device.ts | 16 +++-- packages/common/lib/api/resources/Event.ts | 13 ++-- .../common/lib/api/resources/FeedResource.ts | 4 +- packages/common/lib/api/resources/Image.ts | 4 +- packages/common/lib/api/resources/Marathon.ts | 4 +- .../common/lib/api/resources/MarathonHour.ts | 4 +- .../common/lib/api/resources/Membership.ts | 4 +- .../common/lib/api/resources/Notification.ts | 8 +-- packages/common/lib/api/resources/Person.ts | 4 +- .../common/lib/api/resources/PointEntry.ts | 4 +- .../lib/api/resources/PointOpportunity.ts | 9 ++- packages/common/lib/api/resources/Team.ts | 4 +- packages/common/lib/api/scalars/NodeID.ts | 23 ------- 15 files changed, 97 insertions(+), 77 deletions(-) delete mode 100644 packages/common/lib/api/scalars/NodeID.ts diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index 40879889..069cb6e7 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -1,30 +1,28 @@ -import { Field, InterfaceType, ObjectType } from "type-graphql"; +import { Field, ID, InterfaceType, ObjectType } from "type-graphql"; import { Errorable, ResourceError } from "./resourceError.js"; import { CursorScalar } from "./scalars/Cursor.js"; -import { NodeIDScalar } from "./scalars/NodeID.js"; @InterfaceType() -export class Node { - @Field(() => NodeIDScalar) +export abstract class Node { + @Field(() => ID) id!: string; } @InterfaceType() -export class Edge { +export abstract class Edge { @Field(() => CursorScalar) cursor!: string; @Field(() => Node) - node!: string; + node!: N; } - @InterfaceType({ implements: [Errorable] }) -export class Connection implements Errorable { +export abstract class Connection implements Errorable { @Field(() => Number, { name: "totalCount" }) totalCount!: number; @Field(() => [Edge], { name: "edges" }) - edges!: Edge[]; + edges!: E[]; @Field(() => PageInfo, { name: "pageInfo" }) pageInfo!: PageInfo; @@ -32,25 +30,56 @@ export class Connection implements Errorable { @Field(() => [ResourceError], { name: "errors" }) errors!: ResourceError[]; } - @InterfaceType({ implements: [Errorable] }) -export class Resource implements Errorable { +export abstract class Resource implements Errorable { @Field(() => Node, { name: "node" }) - node!: Node; + node!: N; @Field(() => [ResourceError], { name: "errors" }) errors!: ResourceError[]; } - @InterfaceType({ implements: [Errorable] }) -export class Result implements Errorable { - @Field(() => Node, { name: "node" }) - node!: Node; +export abstract class Result implements Errorable { + @Field(() => Node, { name: "node", nullable: true }) + node?: N; @Field(() => [ResourceError], { name: "errors" }) errors!: ResourceError[]; } +export function createNodeClasses( + cls: new () => T, + name: string +): { + EdgeClass: new () => Edge; + ConnectionClass: new () => Connection>; + ResultClass: new () => Result; +} { + @ObjectType(`Node${name}`, { implements: Edge }) + class EdgeClass extends Edge { + @Field(() => cls) + node!: T; + } + + @ObjectType(`${name}Connection`, { implements: Connection }) + class ConnectionClass extends Connection { + @Field(() => [EdgeClass]) + edges!: EdgeClass[]; + } + + @ObjectType(`${name}Result`, { implements: Result }) + class ResultClass extends Result { + @Field(() => cls, { nullable: true }) + node?: T; + } + + return { + EdgeClass, + ConnectionClass, + ResultClass, + }; +} + @ObjectType() export class PageInfo { @Field(() => Boolean, { diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index c5014686..71115642 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -2,6 +2,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { Node, createNodeClasses } from "../relay.js"; + import { TimestampedResource } from "./Resource.js"; /* @@ -16,9 +18,9 @@ to have additional validation logic in the future. */ @ObjectType() -export class ConfigurationResource extends TimestampedResource { +export class ConfigurationResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) key!: string; @@ -40,3 +42,9 @@ export class ConfigurationResource extends TimestampedResource { return ConfigurationResource.doInit(init); } } + +export const { + ConnectionClass: ConfigurationConnection, + EdgeClass: ConfigurationEdge, + ResultClass: ConfigurationResult, +} = createNodeClasses(ConfigurationResource, "Configuration"); diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index 5df5485a..d6b12479 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -2,22 +2,30 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { Node, createNodeClasses } from "../relay.js"; + import { TimestampedResource } from "./Resource.js"; -@ObjectType() -export class DeviceResource extends TimestampedResource { +@ObjectType({ implements: [TimestampedResource, Node] }) +export class DeviceResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String, { nullable: true }) public expoPushToken!: string | null; @Field(() => DateTimeISOResolver, { nullable: true }) public lastLogin!: DateTime | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { return DeviceResource.doInit(init); } } + +export const { + ConnectionClass: DeviceConnection, + EdgeClass: DeviceEdge, + ResultClass: DeviceResult, +} = createNodeClasses(DeviceResource, "Device"); diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index 7e422986..a2176d0b 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -1,14 +1,13 @@ +import { DateTimeISOResolver } from "graphql-scalars"; import { Interval } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; -import { DateRangeScalar } from "../scalars/DateRangeScalar.js"; - import { Resource, TimestampedResource } from "./Resource.js"; @ObjectType() export class EventResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => [EventOccurrenceResource]) occurrences!: EventOccurrenceResource[]; @Field(() => String) @@ -21,7 +20,7 @@ export class EventResource extends TimestampedResource { location!: string | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { @@ -32,14 +31,14 @@ export class EventResource extends TimestampedResource { @ObjectType() export class EventOccurrenceResource extends Resource { @Field(() => ID) - uuid!: string; - @Field(() => DateRangeScalar) + id!: string; + @Field(() => DateTimeISOResolver) interval!: Interval; @Field(() => Boolean) fullDay!: boolean; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/FeedResource.ts b/packages/common/lib/api/resources/FeedResource.ts index 68c2289c..85bd4704 100644 --- a/packages/common/lib/api/resources/FeedResource.ts +++ b/packages/common/lib/api/resources/FeedResource.ts @@ -16,7 +16,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class FeedResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @@ -25,7 +25,7 @@ export class FeedResource extends TimestampedResource { textContent?: string | null | undefined; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: { diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index e904e2b1..89931420 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -6,7 +6,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class ImageResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => URLResolver, { nullable: true }) url!: URL | null; @@ -27,7 +27,7 @@ export class ImageResource extends TimestampedResource { height!: number; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index 10076863..6daed620 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -6,7 +6,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class MarathonResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) year!: string; @Field(() => DateTimeISOResolver) @@ -33,6 +33,6 @@ export class MarathonResource extends TimestampedResource { } public getUniqueId(): string { - return this.uuid; + return this.id; } } diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 35a8dd6b..238b718b 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -6,7 +6,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class MarathonHourResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @Field(() => String, { nullable: true }) @@ -37,6 +37,6 @@ export class MarathonHourResource extends TimestampedResource { } public getUniqueId(): string { - return this.uuid; + return this.id; } } diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index b68ae9e0..939796f4 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -17,13 +17,13 @@ registerEnumType(MembershipPositionType, { @ObjectType() export class MembershipResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => MembershipPositionType) position!: MembershipPositionType; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index e8d971bd..24175ece 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class NotificationResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @@ -42,7 +42,7 @@ export class NotificationResource extends TimestampedResource { startedSendingAt?: Date | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { @@ -53,7 +53,7 @@ export class NotificationResource extends TimestampedResource { @ObjectType() export class NotificationDeliveryResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => Date, { nullable: true, @@ -87,7 +87,7 @@ export class NotificationDeliveryResource extends TimestampedResource { deliveryError?: string | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 6e91d23d..696eadb2 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -7,7 +7,7 @@ import { RoleResource, defaultRole } from "./Role.js"; @ObjectType() export class PersonResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => [AuthIdPairResource], { deprecationReason: "This is now provided on the AuthIdPair resource.", }) @@ -22,7 +22,7 @@ export class PersonResource extends TimestampedResource { role!: RoleResource; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: { diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index 8d83d56d..c8713ceb 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -5,14 +5,14 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType() export class PointEntryResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String, { nullable: true }) comment!: string | null; @Field(() => Int) points!: number; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index 47a67828..d74a9cd7 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -1,24 +1,23 @@ +import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; -import { DateTimeScalar } from "../scalars/DateTimeScalar.js"; - import { TimestampedResource } from "./Resource.js"; import { TeamType } from "./Team.js"; @ObjectType() export class PointOpportunityResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) name!: string; @Field(() => TeamType) type!: TeamType; - @Field(() => DateTimeScalar, { nullable: true }) + @Field(() => DateTimeISOResolver, { nullable: true }) opportunityDate!: DateTime | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 46a7d436..2ba24c0b 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -36,7 +36,7 @@ registerEnumType(TeamLegacyStatus, { @ObjectType() export class TeamResource extends TimestampedResource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) name!: string; @Field(() => TeamType) @@ -51,7 +51,7 @@ export class TeamResource extends TimestampedResource { persistentIdentifier!: string | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/scalars/NodeID.ts b/packages/common/lib/api/scalars/NodeID.ts deleted file mode 100644 index 18906eb3..00000000 --- a/packages/common/lib/api/scalars/NodeID.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { GraphQLScalarType } from "graphql"; - -export const NodeIDScalar = new GraphQLScalarType({ - name: "NodeID", - description: "Node ID custom scalar type", - parseValue(value): string { - if (typeof value === "string") { - return value; - } else { - throw new TypeError("NodeIDScalar can only parse strings"); - } - }, - serialize(value): string { - if (typeof value === "string") { - return value; - } else { - throw new TypeError("NodeIDScalar can only serialize strings"); - } - }, - parseLiteral(): string { - throw new TypeError("NodeIDScalar should never be used in literal form"); - }, -}); From 191f67171f88bbe4cb975823c7439ce7c9e69966 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 04:09:46 +0000 Subject: [PATCH 008/153] Update id and tweak relay defs --- .../common/lib/api/filtering/list-query-args/FilterItem.ts | 5 ++--- packages/common/lib/api/resources/Marathon.ts | 4 ++-- packages/common/lib/api/resources/MarathonHour.ts | 4 ++-- packages/common/lib/authentication/jwt.ts | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/common/lib/api/filtering/list-query-args/FilterItem.ts b/packages/common/lib/api/filtering/list-query-args/FilterItem.ts index ea3d1a33..7600b38a 100644 --- a/packages/common/lib/api/filtering/list-query-args/FilterItem.ts +++ b/packages/common/lib/api/filtering/list-query-args/FilterItem.ts @@ -7,8 +7,7 @@ import type { OneOfFilterItemInterface, StringFilterItemInterface, } from "@ukdanceblue/common"; -import { DateTimeScalar } from "@ukdanceblue/common"; -import { VoidResolver } from "graphql-scalars"; +import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; import { Field, InputType } from "type-graphql"; import type { Comparator } from "../ListQueryTypes.js"; @@ -104,7 +103,7 @@ export abstract class AbstractDateFilterItem extends FilterItem implements DateFilterItemInterface { - @Field(() => DateTimeScalar) + @Field(() => DateTimeISOResolver) value!: string; @Field(() => NumericComparator, { diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index 6daed620..b0967b4f 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -15,7 +15,7 @@ export class MarathonResource extends TimestampedResource { endDate!: string; static init({ - uuid, + id, year, startDate, endDate, @@ -23,7 +23,7 @@ export class MarathonResource extends TimestampedResource { updatedAt, }: Omit): MarathonResource { return this.doInit({ - uuid, + id, year, startDate, endDate, diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 238b718b..5b7b90e5 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -17,7 +17,7 @@ export class MarathonHourResource extends TimestampedResource { durationInfo!: string; static init({ - uuid, + id, title, details, shownStartingAt, @@ -26,7 +26,7 @@ export class MarathonHourResource extends TimestampedResource { updatedAt, }: Omit): MarathonHourResource { return this.doInit({ - uuid, + id, title, details, shownStartingAt, diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 26125cf9..0fcb8748 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -29,7 +29,7 @@ export function makeUserData( committeeIdentifier: person.role.committeeIdentifier ?? undefined, accessLevel: roleToAccessLevel(person.role), }, - userId: person.uuid, + userId: person.id, teamIds, captainOfTeamIds, authSource, From 7827e0ce9e42271c2e7c59c6dc5e0127abeb6c50 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 04:23:55 +0000 Subject: [PATCH 009/153] Update relay definitions and add new node classes --- packages/common/lib/api/relay.ts | 37 ++++++++++++------- .../common/lib/api/resources/Configuration.ts | 7 ++-- packages/common/lib/api/resources/Device.ts | 10 ++--- packages/common/lib/api/resources/Event.ts | 7 ++++ .../common/lib/api/resources/FeedResource.ts | 10 ++++- packages/common/lib/api/resources/Image.ts | 10 ++++- packages/common/lib/api/resources/Marathon.ts | 8 +++- .../common/lib/api/resources/MarathonHour.ts | 8 +++- .../common/lib/api/resources/Membership.ts | 8 +++- .../common/lib/api/resources/Notification.ts | 1 - packages/common/lib/api/resources/Person.ts | 9 ++++- .../common/lib/api/resources/PointEntry.ts | 8 +++- packages/common/lib/api/resources/Team.ts | 9 ++++- 13 files changed, 93 insertions(+), 39 deletions(-) diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index 069cb6e7..1707c7c6 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -47,36 +47,47 @@ export abstract class Result implements Errorable { errors!: ResourceError[]; } -export function createNodeClasses( +export function createNodeClasses( cls: new () => T, - name: string -): { - EdgeClass: new () => Edge; - ConnectionClass: new () => Connection>; - ResultClass: new () => Result; -} { - @ObjectType(`Node${name}`, { implements: Edge }) + name: Name +) { + const edgeClassName = `${name}Edge` as const; + @ObjectType(edgeClassName, { implements: Edge }) class EdgeClass extends Edge { @Field(() => cls) node!: T; } - @ObjectType(`${name}Connection`, { implements: Connection }) + const connectionClassName = `${name}Connection` as const; + @ObjectType(connectionClassName, { implements: Connection }) class ConnectionClass extends Connection { @Field(() => [EdgeClass]) edges!: EdgeClass[]; } - @ObjectType(`${name}Result`, { implements: Result }) + const resultClassName = `${name}Result` as const; + @ObjectType(resultClassName, { implements: Result }) class ResultClass extends Result { @Field(() => cls, { nullable: true }) node?: T; } return { - EdgeClass, - ConnectionClass, - ResultClass, + [edgeClassName]: EdgeClass, + [connectionClassName]: ConnectionClass, + [resultClassName]: ResultClass, + } as { + // Type magic to let autocomplete work + [K in + | `${Name}Edge` + | `${Name}Connection` + | `${Name}Result`]: K extends `${Name}Edge` + ? typeof EdgeClass + : K extends `${Name}Connection` + ? typeof ConnectionClass + : K extends `${Name}Result` + ? typeof ResultClass + : never; }; } diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index 71115642..f299b0b0 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -5,7 +5,6 @@ import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; - /* The way configurations work is that there can be n number of configurations, each with it's own UUID. When multiple configurations are created with the @@ -44,7 +43,7 @@ export class ConfigurationResource extends TimestampedResource implements Node { } export const { - ConnectionClass: ConfigurationConnection, - EdgeClass: ConfigurationEdge, - ResultClass: ConfigurationResult, + ConfigurationConnection, + ConfigurationEdge, + ConfigurationResult, } = createNodeClasses(ConfigurationResource, "Configuration"); diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index d6b12479..a558c076 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -5,7 +5,6 @@ import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; - @ObjectType({ implements: [TimestampedResource, Node] }) export class DeviceResource extends TimestampedResource implements Node { @Field(() => ID) @@ -24,8 +23,7 @@ export class DeviceResource extends TimestampedResource implements Node { } } -export const { - ConnectionClass: DeviceConnection, - EdgeClass: DeviceEdge, - ResultClass: DeviceResult, -} = createNodeClasses(DeviceResource, "Device"); +export const { DeviceConnection, DeviceEdge, DeviceResult } = createNodeClasses( + DeviceResource, + "Device" +); diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index a2176d0b..8a762a0f 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -2,6 +2,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { Interval } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { createNodeClasses } from "../relay.js"; + import { Resource, TimestampedResource } from "./Resource.js"; @ObjectType() @@ -45,3 +47,8 @@ export class EventOccurrenceResource extends Resource { return EventOccurrenceResource.doInit(init); } } + +export const { EventConnection, EventEdge, EventResult } = createNodeClasses( + EventResource, + "Event" +); diff --git a/packages/common/lib/api/resources/FeedResource.ts b/packages/common/lib/api/resources/FeedResource.ts index 85bd4704..29fcfd83 100644 --- a/packages/common/lib/api/resources/FeedResource.ts +++ b/packages/common/lib/api/resources/FeedResource.ts @@ -1,7 +1,8 @@ import { Field, ID, ObjectType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; // TODO: Expand this to include more types of feed items // export const FeedResourceType = { // FeaturedImage: "FeaturedImage", @@ -14,7 +15,7 @@ import { TimestampedResource } from "./Resource.js"; // }); @ObjectType() -export class FeedResource extends TimestampedResource { +export class FeedResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -38,3 +39,8 @@ export class FeedResource extends TimestampedResource { return FeedResource.doInit(init); } } + +export const { FeedConnection, FeedEdge, FeedResult } = createNodeClasses( + FeedResource, + "Feed" +); diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index 89931420..11284d05 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -1,10 +1,11 @@ import { URLResolver } from "graphql-scalars"; import { Field, ID, Int, ObjectType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; @ObjectType() -export class ImageResource extends TimestampedResource { +export class ImageResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -34,3 +35,8 @@ export class ImageResource extends TimestampedResource { return ImageResource.doInit(init); } } + +export const { ImageConnection, ImageEdge, ImageResult } = createNodeClasses( + ImageResource, + "Image" +); diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index b0967b4f..fb1b73da 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -1,10 +1,11 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { Field, ID, ObjectType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; @ObjectType() -export class MarathonResource extends TimestampedResource { +export class MarathonResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -36,3 +37,6 @@ export class MarathonResource extends TimestampedResource { return this.id; } } + +export const { MarathonConnection, MarathonEdge, MarathonResult } = + createNodeClasses(MarathonResource, "Marathon"); diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 5b7b90e5..21e3a5a5 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -1,10 +1,11 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { Field, ID, ObjectType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; @ObjectType() -export class MarathonHourResource extends TimestampedResource { +export class MarathonHourResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -40,3 +41,6 @@ export class MarathonHourResource extends TimestampedResource { return this.id; } } + +export const { MarathonHourConnection, MarathonHourEdge, MarathonHourResult } = + createNodeClasses(MarathonHourResource, "MarathonHour"); diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index 939796f4..b9ce20d7 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -1,7 +1,8 @@ import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; export const MembershipPositionType = { Member: "Member", Captain: "Captain", @@ -15,7 +16,7 @@ registerEnumType(MembershipPositionType, { }); @ObjectType() -export class MembershipResource extends TimestampedResource { +export class MembershipResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -30,3 +31,6 @@ export class MembershipResource extends TimestampedResource { return MembershipResource.doInit(init); } } + +export const { MembershipConnection, MembershipEdge, MembershipResult } = + createNodeClasses(MembershipResource, "Membership"); diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 24175ece..1a1d7db5 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -5,7 +5,6 @@ import { AccessControl } from "../../authorization/accessControl.js"; import { AccessLevel } from "../../index.js"; import { TimestampedResource } from "./Resource.js"; - @ObjectType() export class NotificationResource extends TimestampedResource { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 696eadb2..7dcfd70a 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -1,11 +1,13 @@ import { Field, ID, ObjectType } from "type-graphql"; +import { Node, createNodeClasses } from "../relay.js"; + import { AuthIdPairResource } from "./AuthIdPair.js"; import { TimestampedResource } from "./Resource.js"; import { RoleResource, defaultRole } from "./Role.js"; @ObjectType() -export class PersonResource extends TimestampedResource { +export class PersonResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => [AuthIdPairResource], { @@ -50,3 +52,8 @@ export class PersonResource extends TimestampedResource { return resource; } } + +export const { PersonConnection, PersonEdge, PersonResult } = createNodeClasses( + PersonResource, + "Person" +); diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index c8713ceb..e8424798 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -1,9 +1,10 @@ import { Field, ID, Int, ObjectType } from "type-graphql"; -import { TimestampedResource } from "./Resource.js"; +import { Node, createNodeClasses } from "../relay.js"; +import { TimestampedResource } from "./Resource.js"; @ObjectType() -export class PointEntryResource extends TimestampedResource { +export class PointEntryResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String, { nullable: true }) @@ -19,3 +20,6 @@ export class PointEntryResource extends TimestampedResource { return PointEntryResource.doInit(init); } } + +export const { PointEntryConnection, PointEntryEdge, PointEntryResult } = + createNodeClasses(PointEntryResource, "PointEntry"); diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 2ba24c0b..7e94f039 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -3,9 +3,9 @@ import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; import { AccessControl } from "../../authorization/accessControl.js"; import { AccessLevel } from "../../authorization/structures.js"; import * as SimpleTypes from "../../utility/primitive/SimpleTypes.js"; +import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; - export const TeamType = { Spirit: "Spirit", Morale: "Morale", @@ -34,7 +34,7 @@ registerEnumType(TeamLegacyStatus, { }); @ObjectType() -export class TeamResource extends TimestampedResource { +export class TeamResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -58,3 +58,8 @@ export class TeamResource extends TimestampedResource { return TeamResource.doInit(init); } } + +export const { TeamConnection, TeamEdge, TeamResult } = createNodeClasses( + TeamResource, + "Team" +); From bfe089c19e8c90c71fd26d1c5ae06393fca8374c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 04:35:53 +0000 Subject: [PATCH 010/153] Refactor file structure and import paths --- packages/common/lib/api/resources/Person.ts | 4 +-- packages/common/lib/api/resources/index.ts | 4 +-- .../api/{resources => types}/AuthIdPair.ts | 3 +- packages/common/lib/api/types/IntervalISO.ts | 33 +++++++++++++++++++ .../lib/api/{resources => types}/Role.ts | 3 +- packages/common/lib/authorization/role.ts | 2 +- 6 files changed, 40 insertions(+), 9 deletions(-) rename packages/common/lib/api/{resources => types}/AuthIdPair.ts (89%) create mode 100644 packages/common/lib/api/types/IntervalISO.ts rename packages/common/lib/api/{resources => types}/Role.ts (96%) diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 7dcfd70a..199a3afd 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -1,10 +1,10 @@ import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import { AuthIdPairResource } from "../types/AuthIdPair.js"; +import { RoleResource, defaultRole } from "../types/Role.js"; -import { AuthIdPairResource } from "./AuthIdPair.js"; import { TimestampedResource } from "./Resource.js"; -import { RoleResource, defaultRole } from "./Role.js"; @ObjectType() export class PersonResource extends TimestampedResource implements Node { diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index b802912d..5bd822ad 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,4 +1,5 @@ -export { AuthIdPairResource } from "./AuthIdPair.js"; +export { AuthIdPairResource } from "../types/AuthIdPair.js"; +export { RoleResource, defaultRole } from "../types/Role.js"; export { ConfigurationResource } from "./Configuration.js"; export { DeviceResource } from "./Device.js"; export { EventOccurrenceResource, EventResource } from "./Event.js"; @@ -15,5 +16,4 @@ export { PersonResource } from "./Person.js"; export { PointEntryResource } from "./PointEntry.js"; export { PointOpportunityResource } from "./PointOpportunity.js"; export { Resource, TimestampedResource } from "./Resource.js"; -export { RoleResource, defaultRole } from "./Role.js"; export { TeamLegacyStatus, TeamResource, TeamType } from "./Team.js"; diff --git a/packages/common/lib/api/resources/AuthIdPair.ts b/packages/common/lib/api/types/AuthIdPair.ts similarity index 89% rename from packages/common/lib/api/resources/AuthIdPair.ts rename to packages/common/lib/api/types/AuthIdPair.ts index a0253ad8..f2e1ae9f 100644 --- a/packages/common/lib/api/resources/AuthIdPair.ts +++ b/packages/common/lib/api/types/AuthIdPair.ts @@ -1,8 +1,7 @@ import { Field, ObjectType } from "type-graphql"; import { AuthSource } from "../../authorization/structures.js"; - -import { Resource } from "./Resource.js"; +import { Resource } from "../resources/Resource.js"; @ObjectType() export class AuthIdPairResource< diff --git a/packages/common/lib/api/types/IntervalISO.ts b/packages/common/lib/api/types/IntervalISO.ts new file mode 100644 index 00000000..e9fcb401 --- /dev/null +++ b/packages/common/lib/api/types/IntervalISO.ts @@ -0,0 +1,33 @@ +import { DateTimeISOResolver } from "graphql-scalars"; +import { DateTime, Interval } from "luxon"; +import { Field, ObjectType } from "type-graphql"; + +@ObjectType() +export class IntervalISO { + @Field(() => DateTimeISOResolver) + readonly start!: Date; + @Field(() => DateTimeISOResolver) + readonly end!: Date; + + get interval(): Interval { + return Interval.fromDateTimes( + DateTime.fromJSDate(this.start), + DateTime.fromJSDate(this.end) + ); + } + + @Field(() => String) + iso8601(): string { + return this.interval.toISO(); + } + + @Field(() => String, { nullable: true }) + duration(): string | null { + return this.interval.toDuration().toISO(); + } + + @Field(() => Boolean) + isEmpty(): boolean { + return this.interval.isEmpty(); + } +} diff --git a/packages/common/lib/api/resources/Role.ts b/packages/common/lib/api/types/Role.ts similarity index 96% rename from packages/common/lib/api/resources/Role.ts rename to packages/common/lib/api/types/Role.ts index 5f4a9cdb..3636052c 100644 --- a/packages/common/lib/api/resources/Role.ts +++ b/packages/common/lib/api/types/Role.ts @@ -12,8 +12,7 @@ import { isCommitteeIdentifier, } from "../../authorization/structures.js"; import { roleToAccessLevel, roleToAuthorization } from "../../index.js"; - -import { Resource } from "./Resource.js"; +import { Resource } from "../resources/Resource.js"; @InputType("RoleResourceInput") @ObjectType() diff --git a/packages/common/lib/authorization/role.ts b/packages/common/lib/authorization/role.ts index 050329d9..12f474cf 100644 --- a/packages/common/lib/authorization/role.ts +++ b/packages/common/lib/authorization/role.ts @@ -1,4 +1,4 @@ -import type { RoleResource } from "../api/resources/Role.js"; +import type { RoleResource } from "../api/types/Role.js"; import type { Authorization } from "./structures.js"; import { From 29999ad2a02196b5222f7729c9fd7a46dc3f7644 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 21:52:21 +0000 Subject: [PATCH 011/153] Add IntervalISO type and update import paths --- packages/common/lib/api/resources/index.ts | 5 +++++ packages/common/lib/index.ts | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index 5bd822ad..15d150d3 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,5 +1,7 @@ export { AuthIdPairResource } from "../types/AuthIdPair.js"; +export { IntervalISO } from "../types/IntervalISO.js"; export { RoleResource, defaultRole } from "../types/Role.js"; + export { ConfigurationResource } from "./Configuration.js"; export { DeviceResource } from "./Device.js"; export { EventOccurrenceResource, EventResource } from "./Event.js"; @@ -17,3 +19,6 @@ export { PointEntryResource } from "./PointEntry.js"; export { PointOpportunityResource } from "./PointOpportunity.js"; export { Resource, TimestampedResource } from "./Resource.js"; export { TeamLegacyStatus, TeamResource, TeamType } from "./Team.js"; + +export * from "../relay.js"; +export * from "../resourceError.js"; diff --git a/packages/common/lib/index.ts b/packages/common/lib/index.ts index 2c62688d..dc632569 100644 --- a/packages/common/lib/index.ts +++ b/packages/common/lib/index.ts @@ -36,10 +36,6 @@ export * from "./utility/time/intervalTools.js"; export * from "./api/resources/index.js"; export * from "./utility/errors/DetailedError.js"; -export * from "./api/scalars/DateRangeScalar.js"; -export * from "./api/scalars/DateTimeScalar.js"; -export * from "./api/scalars/DurationScalar.js"; - export * from "./api/filtering/list-query-args/FilterItem.js"; export * from "./api/filtering/list-query-args/FilteredListQueryArgs.js"; export * from "./api/filtering/list-query-args/UnfilteredListQueryArgs.js"; From e9ef363b10e0f8199861cd625dcbd082bf35bc8d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 22:06:53 +0000 Subject: [PATCH 012/153] Refactor GraphQL schema and update import paths --- new-desing.graphql | 12 ++--- .../UnfilteredListQueryArgs.ts | 4 +- .../common/lib/api/resources/Configuration.ts | 21 ++++++--- packages/common/lib/api/resources/Device.ts | 5 +-- packages/common/lib/api/resources/Person.ts | 8 ++-- packages/common/lib/api/resources/Resource.ts | 20 +++++++++ packages/common/lib/api/resources/index.ts | 44 ++++++++++++------- packages/common/lib/api/types/Role.ts | 14 +++--- packages/common/lib/authorization/role.ts | 4 +- .../common/lib/utility/time/intervalTools.ts | 36 +++++++++------ 10 files changed, 105 insertions(+), 63 deletions(-) diff --git a/new-desing.graphql b/new-desing.graphql index 853adb8b..ffd2795e 100644 --- a/new-desing.graphql +++ b/new-desing.graphql @@ -266,7 +266,7 @@ type Configuration { createdAt: DateTimeISO } -type MobileAppConfiguration { +type MobileAppConfiguration { # TODO shownTabs: [MobileAppTab!]! fancyTab: MobileAppTab allowedLoginTypes: [AuthSource!]! @@ -485,11 +485,13 @@ type Notification { type Person { uuid: UUID! - role: Role! teams: [Membership!]! primaryCommittee: Committee + primaryCommitteeRole: CommitteeRole committees: [Committee!]! + dbRole: DbRole! + name: String email: String! linkblue: String @@ -533,12 +535,6 @@ type PointOpportunity { createdAt: DateTimeISO } -type Role { - committee: Committee - committeeRole: CommitteeRole - dbRole: DbRole! -} - type Team { uuid: UUID! diff --git a/packages/common/lib/api/filtering/list-query-args/UnfilteredListQueryArgs.ts b/packages/common/lib/api/filtering/list-query-args/UnfilteredListQueryArgs.ts index 63e69562..10163703 100644 --- a/packages/common/lib/api/filtering/list-query-args/UnfilteredListQueryArgs.ts +++ b/packages/common/lib/api/filtering/list-query-args/UnfilteredListQueryArgs.ts @@ -1,4 +1,4 @@ -import type { OptionalToNullable, Resource } from "@ukdanceblue/common"; +import type { Node, OptionalToNullable } from "@ukdanceblue/common"; import { ArgsType, Field, Int } from "type-graphql"; import type { ListQueryType } from "../ListQueryTypes.js"; @@ -8,7 +8,7 @@ import { DEFAULT_PAGE_SIZE, FIRST_PAGE } from "./common.js"; @ArgsType() export class UnfilteredListQueryArgs - implements OptionalToNullable>> + implements OptionalToNullable>> { @Field(() => Boolean, { nullable: true, diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index f299b0b0..9fb81005 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -1,7 +1,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; -import type { DateTime } from "luxon"; +import { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -17,7 +18,7 @@ to have additional validation logic in the future. */ @ObjectType() -export class ConfigurationResource extends TimestampedResource implements Node { +export class ConfigurationNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -28,17 +29,23 @@ export class ConfigurationResource extends TimestampedResource implements Node { value!: string; @Field(() => DateTimeISOResolver, { nullable: true }) - validAfter!: DateTime | null; + validAfter?: Date | null; + get validAfterDateTime(): DateTime | null { + return dateTimeFromSomething(this.validAfter ?? null); + } @Field(() => DateTimeISOResolver, { nullable: true }) - validUntil!: DateTime | null; + validUntil?: Date | null; + get validUntilDateTime(): DateTime | null { + return dateTimeFromSomething(this.validUntil ?? null); + } public getUniqueId(): string { return this.key; } - public static init(init: Partial) { - return ConfigurationResource.doInit(init); + public static init(init: Partial) { + return ConfigurationNode.doInit(init); } } @@ -46,4 +53,4 @@ export const { ConfigurationConnection, ConfigurationEdge, ConfigurationResult, -} = createNodeClasses(ConfigurationResource, "Configuration"); +} = createNodeClasses(ConfigurationNode, "Configuration"); diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index a558c076..49e60611 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -1,5 +1,4 @@ import { DateTimeISOResolver } from "graphql-scalars"; -import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; @@ -9,10 +8,8 @@ import { TimestampedResource } from "./Resource.js"; export class DeviceResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; - @Field(() => String, { nullable: true }) - public expoPushToken!: string | null; @Field(() => DateTimeISOResolver, { nullable: true }) - public lastLogin!: DateTime | null; + public lastLogin!: Date | null; public getUniqueId(): string { return this.id; diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 199a3afd..9e630cf2 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -2,7 +2,7 @@ import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; import { AuthIdPairResource } from "../types/AuthIdPair.js"; -import { RoleResource, defaultRole } from "../types/Role.js"; +import { Role, defaultRole } from "../types/Role.js"; import { TimestampedResource } from "./Resource.js"; @@ -20,8 +20,8 @@ export class PersonResource extends TimestampedResource implements Node { email!: string; @Field(() => String, { nullable: true }) linkblue!: string | null; - @Field(() => RoleResource) - role!: RoleResource; + @Field(() => Role) + role!: Role; public getUniqueId(): string { return this.id; @@ -33,7 +33,7 @@ export class PersonResource extends TimestampedResource implements Node { name?: string | null; email: string; linkblue?: string | null; - role?: RoleResource | null; + role?: Role | null; createdAt?: Date | null; updatedAt?: Date | null; }) { diff --git a/packages/common/lib/api/resources/Resource.ts b/packages/common/lib/api/resources/Resource.ts index 86648601..0e199a81 100644 --- a/packages/common/lib/api/resources/Resource.ts +++ b/packages/common/lib/api/resources/Resource.ts @@ -1,6 +1,11 @@ +import type { DateTime } from "luxon"; import { Field, ObjectType } from "type-graphql"; import type { Class } from "utility-types"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; + +import { PersonResource } from "./Person.js"; + @ObjectType() export abstract class Resource { /** @@ -27,6 +32,21 @@ export abstract class Resource { export abstract class TimestampedResource extends Resource { @Field(() => Date, { nullable: true }) createdAt?: Date | null; + get createdAtDateTime(): DateTime | null { + return dateTimeFromSomething(this.createdAt ?? null); + } + @Field(() => Date, { nullable: true }) updatedAt?: Date | null; + get updatedAtDateTime(): DateTime | null { + return dateTimeFromSomething(this.updatedAt ?? null); + } +} + +@ObjectType() +export abstract class TrackedResource extends TimestampedResource { + @Field(() => PersonResource, { nullable: true }) + createdBy?: PersonResource | null; + @Field(() => PersonResource, { nullable: true }) + updatedBy?: PersonResource | null; } diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index 15d150d3..eb9dcf75 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,24 +1,38 @@ -export { AuthIdPairResource } from "../types/AuthIdPair.js"; +export { AuthIdPairResource as AuthIdPairNode } from "../types/AuthIdPair.js"; export { IntervalISO } from "../types/IntervalISO.js"; -export { RoleResource, defaultRole } from "../types/Role.js"; +export { Role as RoleResource, defaultRole } from "../types/Role.js"; -export { ConfigurationResource } from "./Configuration.js"; -export { DeviceResource } from "./Device.js"; -export { EventOccurrenceResource, EventResource } from "./Event.js"; -export { FeedResource } from "./FeedResource.js"; -export { ImageResource } from "./Image.js"; +export { ConfigurationNode } from "./Configuration.js"; +export { DeviceResource as DeviceNode } from "./Device.js"; +export { + EventResource as EventNode, + EventOccurrenceResource as EventOccurrenceNode, +} from "./Event.js"; +export { FeedResource as FeedNode } from "./FeedResource.js"; +export { ImageResource as ImageNode } from "./Image.js"; export * from "./Marathon.js"; export * from "./MarathonHour.js"; -export { MembershipPositionType, MembershipResource } from "./Membership.js"; export { - NotificationDeliveryResource, - NotificationResource, + MembershipResource as MembershipNode, + MembershipPositionType, +} from "./Membership.js"; +export { + NotificationDeliveryResource as NotificationDeliveryNode, + NotificationResource as NotificationNode, } from "./Notification.js"; -export { PersonResource } from "./Person.js"; -export { PointEntryResource } from "./PointEntry.js"; -export { PointOpportunityResource } from "./PointOpportunity.js"; -export { Resource, TimestampedResource } from "./Resource.js"; -export { TeamLegacyStatus, TeamResource, TeamType } from "./Team.js"; +export { PersonResource as PersonNode } from "./Person.js"; +export { PointEntryResource as PointEntryNode } from "./PointEntry.js"; +export { PointOpportunityResource as PointOpportunityNode } from "./PointOpportunity.js"; +export { + Resource as Node, + TimestampedResource as TimestampedNode, + TrackedResource as TrackedNode, +} from "./Resource.js"; +export { + TeamLegacyStatus, + TeamResource as TeamNode, + TeamType, +} from "./Team.js"; export * from "../relay.js"; export * from "../resourceError.js"; diff --git a/packages/common/lib/api/types/Role.ts b/packages/common/lib/api/types/Role.ts index 3636052c..2d5d90b1 100644 --- a/packages/common/lib/api/types/Role.ts +++ b/packages/common/lib/api/types/Role.ts @@ -16,7 +16,7 @@ import { Resource } from "../resources/Resource.js"; @InputType("RoleResourceInput") @ObjectType() -export class RoleResource extends Resource { +export class Role extends Resource { @Field(() => DbRole, { defaultValue: DbRole.None }) dbRole!: DbRole; @Field(() => CommitteeRole, { nullable: true }) @@ -24,14 +24,12 @@ export class RoleResource extends Resource { @Field(() => CommitteeIdentifier, { nullable: true }) committeeIdentifier!: CommitteeIdentifier | null; - public static init(init: Partial) { - return RoleResource.doInit(init); + public static init(init: Partial) { + return Role.doInit(init); } - static fromAuthorization( - authorization: Readonly - ): RoleResource { - const partial: Partial = {}; + static fromAuthorization(authorization: Readonly): Role { + const partial: Partial = {}; partial.dbRole = authorization.dbRole; partial.committeeRole = authorization.committeeRole ?? null; if (isCommitteeIdentifier(authorization.committeeIdentifier)) { @@ -50,4 +48,4 @@ export class RoleResource extends Resource { } } -export const defaultRole = RoleResource.fromAuthorization(defaultAuthorization); +export const defaultRole = Role.fromAuthorization(defaultAuthorization); diff --git a/packages/common/lib/authorization/role.ts b/packages/common/lib/authorization/role.ts index 12f474cf..eada1d61 100644 --- a/packages/common/lib/authorization/role.ts +++ b/packages/common/lib/authorization/role.ts @@ -1,4 +1,4 @@ -import type { RoleResource } from "../api/types/Role.js"; +import type { Role } from "../api/types/Role.js"; import type { Authorization } from "./structures.js"; import { @@ -61,7 +61,7 @@ export function roleToAccessLevel(role: { * @return An Authorization object representing the same role * @throws Error if one of committee or committeeRole is set without the other */ -export function roleToAuthorization(role: RoleResource): Authorization { +export function roleToAuthorization(role: Role): Authorization { const auth: Authorization = { dbRole: role.dbRole, accessLevel: roleToAccessLevel(role), diff --git a/packages/common/lib/utility/time/intervalTools.ts b/packages/common/lib/utility/time/intervalTools.ts index c7d7f933..9a09040d 100644 --- a/packages/common/lib/utility/time/intervalTools.ts +++ b/packages/common/lib/utility/time/intervalTools.ts @@ -29,40 +29,50 @@ export function validateInterval( export function dateTimeFromSomething( something: string | number | Date | DateTime -): DateTime; +): DateTime; export function dateTimeFromSomething(something: null): null; export function dateTimeFromSomething(something: undefined): undefined; export function dateTimeFromSomething( something: string | number | Date | DateTime | null -): DateTime | null; +): DateTime | null; export function dateTimeFromSomething( something: string | number | Date | DateTime | undefined -): DateTime | undefined; +): DateTime | undefined; export function dateTimeFromSomething( something: string | number | Date | DateTime | null | undefined -): DateTime | null | undefined; +): DateTime | null | undefined; export function dateTimeFromSomething( something: string | number | Date | DateTime | null | undefined -): DateTime | null | undefined { +): DateTime | null | undefined { if (something == null) { return something; } + let dateTime = null; switch (typeof something) { case "string": { - return DateTime.fromISO(something); + dateTime = DateTime.fromISO(something); + break; } case "number": { - return DateTime.fromMillis(something); + dateTime = DateTime.fromMillis(something); + break; } case "object": { - return something instanceof Date - ? DateTime.fromJSDate(something) - : DateTime.isDateTime(something) - ? something - : DateTime.invalid("Invalid input type for dateTimeFromSomething"); + dateTime = + something instanceof Date + ? DateTime.fromJSDate(something) + : DateTime.isDateTime(something) + ? something + : DateTime.invalid("Invalid input type for dateTimeFromSomething"); + break; } default: { - return DateTime.invalid("Invalid input type for dateTimeFromSomething"); + dateTime = DateTime.invalid( + "Invalid input type for dateTimeFromSomething" + ); + break; } } + + return dateTime.isValid ? dateTime : null; } From b1e7a993ef6068604542cc07ec452ce86536995d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 21 Apr 2024 22:30:18 +0000 Subject: [PATCH 013/153] Refactor GraphQL schema and update import paths --- packages/common/lib/api/resources/Device.ts | 8 +++++++- packages/common/lib/api/resources/Event.ts | 7 +++---- packages/common/lib/api/resources/Marathon.ts | 12 +++++++++-- .../common/lib/api/resources/MarathonHour.ts | 7 ++++++- .../common/lib/api/resources/Notification.ts | 20 ++++++++++++++----- .../lib/api/resources/PointOpportunity.ts | 7 ++++++- packages/common/lib/api/resources/Resource.ts | 10 ---------- packages/common/lib/api/resources/index.ts | 1 - packages/common/lib/api/types/IntervalISO.ts | 14 +++++++++---- 9 files changed, 57 insertions(+), 29 deletions(-) diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index 49e60611..6e66e5ef 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -1,6 +1,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; +import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -8,8 +10,12 @@ import { TimestampedResource } from "./Resource.js"; export class DeviceResource extends TimestampedResource implements Node { @Field(() => ID) id!: string; + @Field(() => DateTimeISOResolver, { nullable: true }) - public lastLogin!: Date | null; + public lastLogin?: Date | null; + get lastLoginDateTime(): DateTime | null { + return dateTimeFromSomething(this.lastLogin ?? null); + } public getUniqueId(): string { return this.id; diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index 8a762a0f..28626e12 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -1,8 +1,7 @@ -import { DateTimeISOResolver } from "graphql-scalars"; -import { Interval } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { createNodeClasses } from "../relay.js"; +import { IntervalISO } from "../types/IntervalISO.js"; import { Resource, TimestampedResource } from "./Resource.js"; @@ -34,8 +33,8 @@ export class EventResource extends TimestampedResource { export class EventOccurrenceResource extends Resource { @Field(() => ID) id!: string; - @Field(() => DateTimeISOResolver) - interval!: Interval; + @Field(() => IntervalISO) + interval!: IntervalISO; @Field(() => Boolean) fullDay!: boolean; diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index fb1b73da..e64b9957 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -1,6 +1,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; +import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -11,9 +13,15 @@ export class MarathonResource extends TimestampedResource implements Node { @Field(() => String) year!: string; @Field(() => DateTimeISOResolver) - startDate!: string; + startDate!: Date; + get startDateDateTime(): DateTime { + return dateTimeFromSomething(this.startDate); + } @Field(() => DateTimeISOResolver) - endDate!: string; + endDate!: Date; + get endDateDateTime(): DateTime { + return dateTimeFromSomething(this.endDate); + } static init({ id, diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 21e3a5a5..d56d440b 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -1,6 +1,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; +import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -13,7 +15,10 @@ export class MarathonHourResource extends TimestampedResource implements Node { @Field(() => String, { nullable: true }) details?: string | null; @Field(() => DateTimeISOResolver) - shownStartingAt!: string; + shownStartingAt!: Date; + get shownStartingAtDateTime(): DateTime { + return dateTimeFromSomething(this.shownStartingAt); + } @Field(() => String) durationInfo!: string; diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 1a1d7db5..826ebb1a 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -1,8 +1,9 @@ -import { URLResolver } from "graphql-scalars"; +import { DateTimeISOResolver, URLResolver } from "graphql-scalars"; +import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { AccessControl } from "../../authorization/accessControl.js"; -import { AccessLevel } from "../../index.js"; +import { AccessLevel, dateTimeFromSomething } from "../../index.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType() @@ -23,22 +24,31 @@ export class NotificationResource extends TimestampedResource { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) deliveryIssue?: string | null; - @Field(() => Date, { nullable: true }) + @Field(() => DateTimeISOResolver, { nullable: true }) @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) deliveryIssueAcknowledgedAt?: Date | null; + get deliveryIssueAcknowledgedAtDateTime(): DateTime | null { + return dateTimeFromSomething(this.deliveryIssueAcknowledgedAt ?? null); + } - @Field(() => Date, { + @Field(() => DateTimeISOResolver, { nullable: true, description: "The time the notification is scheduled to be sent, if null it is either already sent or unscheduled.", }) sendAt?: Date | null; + get sendAtDateTime(): DateTime | null { + return dateTimeFromSomething(this.sendAt ?? null); + } - @Field(() => Date, { + @Field(() => DateTimeISOResolver, { nullable: true, description: "The time the server started sending the notification.", }) startedSendingAt?: Date | null; + get startedSendingAtDateTime(): DateTime | null { + return dateTimeFromSomething(this.startedSendingAt ?? null); + } public getUniqueId(): string { return this.id; diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index d74a9cd7..a4f59033 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -2,6 +2,8 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; + import { TimestampedResource } from "./Resource.js"; import { TeamType } from "./Team.js"; @@ -14,7 +16,10 @@ export class PointOpportunityResource extends TimestampedResource { @Field(() => TeamType) type!: TeamType; @Field(() => DateTimeISOResolver, { nullable: true }) - opportunityDate!: DateTime | null; + opportunityDate!: Date | null; + get opportunityDateTime(): DateTime | null { + return dateTimeFromSomething(this.opportunityDate ?? null); + } public getUniqueId(): string { return this.id; diff --git a/packages/common/lib/api/resources/Resource.ts b/packages/common/lib/api/resources/Resource.ts index 0e199a81..64c74c66 100644 --- a/packages/common/lib/api/resources/Resource.ts +++ b/packages/common/lib/api/resources/Resource.ts @@ -4,8 +4,6 @@ import type { Class } from "utility-types"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; -import { PersonResource } from "./Person.js"; - @ObjectType() export abstract class Resource { /** @@ -42,11 +40,3 @@ export abstract class TimestampedResource extends Resource { return dateTimeFromSomething(this.updatedAt ?? null); } } - -@ObjectType() -export abstract class TrackedResource extends TimestampedResource { - @Field(() => PersonResource, { nullable: true }) - createdBy?: PersonResource | null; - @Field(() => PersonResource, { nullable: true }) - updatedBy?: PersonResource | null; -} diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index eb9dcf75..d4fd388f 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -26,7 +26,6 @@ export { PointOpportunityResource as PointOpportunityNode } from "./PointOpportu export { Resource as Node, TimestampedResource as TimestampedNode, - TrackedResource as TrackedNode, } from "./Resource.js"; export { TeamLegacyStatus, diff --git a/packages/common/lib/api/types/IntervalISO.ts b/packages/common/lib/api/types/IntervalISO.ts index e9fcb401..ee866c23 100644 --- a/packages/common/lib/api/types/IntervalISO.ts +++ b/packages/common/lib/api/types/IntervalISO.ts @@ -2,18 +2,24 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { DateTime, Interval } from "luxon"; import { Field, ObjectType } from "type-graphql"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; + @ObjectType() export class IntervalISO { @Field(() => DateTimeISOResolver) readonly start!: Date; + get startDateTime(): DateTime { + return dateTimeFromSomething(this.start); + } + @Field(() => DateTimeISOResolver) readonly end!: Date; + get endDateTime(): DateTime { + return dateTimeFromSomething(this.end); + } get interval(): Interval { - return Interval.fromDateTimes( - DateTime.fromJSDate(this.start), - DateTime.fromJSDate(this.end) - ); + return Interval.fromDateTimes(this.startDateTime, this.endDateTime); } @Field(() => String) From 19a84d8a88c37304e4eb117e624208a7399ddd2d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 04:41:33 +0000 Subject: [PATCH 014/153] Refactor GraphQL schema and update import paths --- packages/common/lib/api/relay.ts | 2 +- .../common/lib/api/resources/Configuration.ts | 6 ++- packages/common/lib/api/resources/Device.ts | 4 +- packages/common/lib/api/resources/Event.ts | 20 ++++++---- .../resources/{FeedResource.ts => Feed.ts} | 8 ++-- packages/common/lib/api/resources/Image.ts | 8 ++-- packages/common/lib/api/resources/Marathon.ts | 10 +++-- .../common/lib/api/resources/MarathonHour.ts | 12 +++--- .../common/lib/api/resources/Membership.ts | 8 ++-- .../common/lib/api/resources/Notification.ts | 39 ++++++++++++++----- packages/common/lib/api/resources/Person.ts | 25 +++++------- .../common/lib/api/resources/PointEntry.ts | 8 ++-- .../lib/api/resources/PointOpportunity.ts | 14 +++++-- packages/common/lib/api/resources/Team.ts | 17 +++----- packages/common/lib/api/resources/index.ts | 2 +- packages/common/lib/authentication/jwt.ts | 2 +- 16 files changed, 109 insertions(+), 76 deletions(-) rename packages/common/lib/api/resources/{FeedResource.ts => Feed.ts} (91%) diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index 1707c7c6..49d17eec 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -6,7 +6,7 @@ import { CursorScalar } from "./scalars/Cursor.js"; @InterfaceType() export abstract class Node { @Field(() => ID) - id!: string; + uuid!: string; } @InterfaceType() export abstract class Edge { diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index 9fb81005..b30b04d5 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -17,10 +17,12 @@ This also means we have some of the logic we need for a configuration to have additional validation logic in the future. */ -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class ConfigurationNode extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) key!: string; diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index 6e66e5ef..9028796d 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node] }) export class DeviceResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => DateTimeISOResolver, { nullable: true }) public lastLogin?: Date | null; @@ -18,7 +18,7 @@ export class DeviceResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index 28626e12..c8bde3ee 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -1,14 +1,16 @@ import { Field, ID, ObjectType } from "type-graphql"; -import { createNodeClasses } from "../relay.js"; +import { Node, createNodeClasses } from "../relay.js"; import { IntervalISO } from "../types/IntervalISO.js"; import { Resource, TimestampedResource } from "./Resource.js"; -@ObjectType() -export class EventResource extends TimestampedResource { +@ObjectType({ + implements: [TimestampedResource, Node], +}) +export class EventResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => [EventOccurrenceResource]) occurrences!: EventOccurrenceResource[]; @Field(() => String) @@ -21,7 +23,7 @@ export class EventResource extends TimestampedResource { location!: string | null; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { @@ -29,17 +31,19 @@ export class EventResource extends TimestampedResource { } } -@ObjectType() +@ObjectType({ + implements: [Resource], +}) export class EventOccurrenceResource extends Resource { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => IntervalISO) interval!: IntervalISO; @Field(() => Boolean) fullDay!: boolean; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/FeedResource.ts b/packages/common/lib/api/resources/Feed.ts similarity index 91% rename from packages/common/lib/api/resources/FeedResource.ts rename to packages/common/lib/api/resources/Feed.ts index 29fcfd83..23dc5c85 100644 --- a/packages/common/lib/api/resources/FeedResource.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -14,10 +14,12 @@ import { TimestampedResource } from "./Resource.js"; // description: "Dictates how to interpret the resource link", // }); -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class FeedResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) title!: string; @@ -26,7 +28,7 @@ export class FeedResource extends TimestampedResource implements Node { textContent?: string | null | undefined; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: { diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index 11284d05..489e633a 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -4,10 +4,12 @@ import { Field, ID, Int, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class ImageResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => URLResolver, { nullable: true }) url!: URL | null; @@ -28,7 +30,7 @@ export class ImageResource extends TimestampedResource implements Node { height!: number; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index e64b9957..6e65acf6 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -6,10 +6,12 @@ import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class MarathonResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) year!: string; @Field(() => DateTimeISOResolver) @@ -24,7 +26,7 @@ export class MarathonResource extends TimestampedResource implements Node { } static init({ - id, + uuid: id, year, startDate, endDate, @@ -42,7 +44,7 @@ export class MarathonResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.uuid; } } diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index d56d440b..d6358d57 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -6,10 +6,12 @@ import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class MarathonHourResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) title!: string; @Field(() => String, { nullable: true }) @@ -23,7 +25,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { durationInfo!: string; static init({ - id, + uuid, title, details, shownStartingAt, @@ -32,7 +34,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { updatedAt, }: Omit): MarathonHourResource { return this.doInit({ - id, + uuid, title, details, shownStartingAt, @@ -43,7 +45,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.uuid; } } diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index b9ce20d7..d7331237 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -15,16 +15,18 @@ registerEnumType(MembershipPositionType, { description: "The position of a member on a team", }); -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class MembershipResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => MembershipPositionType) position!: MembershipPositionType; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 826ebb1a..106b5dd0 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -3,13 +3,20 @@ import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { AccessControl } from "../../authorization/accessControl.js"; -import { AccessLevel, dateTimeFromSomething } from "../../index.js"; +import { + AccessLevel, + createNodeClasses, + dateTimeFromSomething, +} from "../../index.js"; +import { Node } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() -export class NotificationResource extends TimestampedResource { +@ObjectType({ + implements: [TimestampedResource, Node], +}) +export class NotificationResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) title!: string; @@ -51,7 +58,7 @@ export class NotificationResource extends TimestampedResource { } public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { @@ -59,10 +66,18 @@ export class NotificationResource extends TimestampedResource { } } -@ObjectType() -export class NotificationDeliveryResource extends TimestampedResource { +export const { NotificationConnection, NotificationEdge, NotificationResult } = + createNodeClasses(NotificationResource, "Notification"); + +@ObjectType({ + implements: [TimestampedResource, Node], +}) +export class NotificationDeliveryResource + extends TimestampedResource + implements Node +{ @Field(() => ID) - id!: string; + uuid!: string; @Field(() => Date, { nullable: true, @@ -96,10 +111,16 @@ export class NotificationDeliveryResource extends TimestampedResource { deliveryError?: string | null; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { return NotificationDeliveryResource.doInit(init); } } + +export const { + NotificationDeliveryConnection, + NotificationDeliveryEdge, + NotificationDeliveryResult, +} = createNodeClasses(NotificationDeliveryResource, "NotificationDelivery"); diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 9e630cf2..8cfd1c6a 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -1,39 +1,35 @@ import { Field, ID, ObjectType } from "type-graphql"; +import { DbRole } from "../../authorization/structures.js"; import { Node, createNodeClasses } from "../relay.js"; -import { AuthIdPairResource } from "../types/AuthIdPair.js"; -import { Role, defaultRole } from "../types/Role.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class PersonResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; - @Field(() => [AuthIdPairResource], { - deprecationReason: "This is now provided on the AuthIdPair resource.", - }) - authIds!: AuthIdPairResource[]; + uuid!: string; @Field(() => String, { nullable: true }) name!: string | null; @Field(() => String) email!: string; @Field(() => String, { nullable: true }) linkblue!: string | null; - @Field(() => Role) - role!: Role; + @Field(() => DbRole) + dbRole!: DbRole; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: { uuid: string; - authIds?: AuthIdPairResource[] | null; name?: string | null; email: string; linkblue?: string | null; - role?: Role | null; + dbRole?: DbRole | null; createdAt?: Date | null; updatedAt?: Date | null; }) { @@ -42,10 +38,9 @@ export class PersonResource extends TimestampedResource implements Node { email: init.email, }); - resource.authIds = init.authIds ?? []; resource.name = init.name ?? null; resource.linkblue = init.linkblue ?? null; - resource.role = init.role ?? defaultRole; + resource.dbRole = init.dbRole ?? DbRole.None; resource.createdAt = init.createdAt ?? null; resource.updatedAt = init.updatedAt ?? null; diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index e8424798..03b8635b 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -3,17 +3,19 @@ import { Field, ID, Int, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class PointEntryResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String, { nullable: true }) comment!: string | null; @Field(() => Int) points!: number; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index a4f59033..82390f02 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -3,14 +3,20 @@ import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; +import { Node } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; import { TeamType } from "./Team.js"; -@ObjectType() -export class PointOpportunityResource extends TimestampedResource { +@ObjectType({ + implements: [TimestampedResource, Node], +}) +export class PointOpportunityResource + extends TimestampedResource + implements Node +{ @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) name!: string; @Field(() => TeamType) @@ -22,7 +28,7 @@ export class PointOpportunityResource extends TimestampedResource { } public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 7e94f039..22895803 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -1,8 +1,5 @@ import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; -import { AccessControl } from "../../authorization/accessControl.js"; -import { AccessLevel } from "../../authorization/structures.js"; -import * as SimpleTypes from "../../utility/primitive/SimpleTypes.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -33,25 +30,21 @@ registerEnumType(TeamLegacyStatus, { description: "New Team vs Returning Team", }); -@ObjectType() +@ObjectType({ + implements: [TimestampedResource, Node], +}) export class TeamResource extends TimestampedResource implements Node { @Field(() => ID) - id!: string; + uuid!: string; @Field(() => String) name!: string; @Field(() => TeamType) type!: TeamType; @Field(() => TeamLegacyStatus) legacyStatus!: TeamLegacyStatus; - @Field(() => String) - marathonYear!: SimpleTypes.MarathonYearString; - - @AccessControl({ accessLevel: AccessLevel.Committee }) - @Field(() => String, { nullable: true }) - persistentIdentifier!: string | null; public getUniqueId(): string { - return this.id; + return this.uuid; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index d4fd388f..b965c170 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -8,7 +8,7 @@ export { EventResource as EventNode, EventOccurrenceResource as EventOccurrenceNode, } from "./Event.js"; -export { FeedResource as FeedNode } from "./FeedResource.js"; +export { FeedResource as FeedNode } from "./Feed.js"; export { ImageResource as ImageNode } from "./Image.js"; export * from "./Marathon.js"; export * from "./MarathonHour.js"; diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 0fcb8748..26125cf9 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -29,7 +29,7 @@ export function makeUserData( committeeIdentifier: person.role.committeeIdentifier ?? undefined, accessLevel: roleToAccessLevel(person.role), }, - userId: person.id, + userId: person.uuid, teamIds, captainOfTeamIds, authSource, From be7d1a9d3c307ac0901a239ce798c4cd843fedc0 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 04:58:46 +0000 Subject: [PATCH 015/153] Refactor file structure and update import paths --- packages/common/lib/api/relay.ts | 62 +++++++------- packages/common/lib/api/resources/Device.ts | 8 +- .../lib/api/resources/authorization.test.ts | 68 ++++++++++++---- packages/common/lib/api/resources/index.ts | 3 +- packages/common/lib/api/types/Role.ts | 51 ------------ packages/common/lib/authentication/jwt.ts | 14 ++-- .../common/lib/authorization/accessControl.ts | 80 +++++++++++------- .../common/lib/authorization/role.test.ts | 81 +++++-------------- packages/common/lib/authorization/role.ts | 71 +++++++--------- .../common/lib/authorization/structures.ts | 7 +- 10 files changed, 200 insertions(+), 245 deletions(-) delete mode 100644 packages/common/lib/api/types/Role.ts diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index 49d17eec..d4001fe9 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -3,6 +3,37 @@ import { Field, ID, InterfaceType, ObjectType } from "type-graphql"; import { Errorable, ResourceError } from "./resourceError.js"; import { CursorScalar } from "./scalars/Cursor.js"; +@ObjectType() +export class PageInfo { + @Field(() => Boolean, { + name: "hasPreviousPage", + description: + "hasPreviousPage is used to indicate whether more edges exist prior to the set defined by the clients arguments. If the client is paginating with last/before, then the server must return true if prior edges exist, otherwise false. If the client is paginating with first/after, then the client may return true if edges prior to after exist, if it can do so efficiently, otherwise may return false.", + }) + hasPreviousPage!: boolean; + + @Field(() => Boolean, { + name: "hasNextPage", + description: + "hasNextPage is used to indicate whether more edges exist following the set defined by the clients arguments. If the client is paginating with first/after, then the server must return true if further edges exist, otherwise false. If the client is paginating with last/before, then the client may return true if edges further from before exist, if it can do so efficiently, otherwise may return false.", + }) + hasNextPage!: boolean; + + @Field(() => CursorScalar, { + name: "startCursor", + description: + "startCursor is simply an opaque value that refers to the first position in a connection. It is used by the client to request the first set of edges in a connection. The server must return the cursor that corresponds to the first element in the connection.", + }) + startCursor!: string; + + @Field(() => CursorScalar, { + name: "endCursor", + description: + "endCursor is simply an opaque value that refers to the last position in a connection. It is used by the client to request the last set of edges in a connection. The server must return the cursor that corresponds to the last element in the connection.", + }) + endCursor!: string; +} + @InterfaceType() export abstract class Node { @Field(() => ID) @@ -90,34 +121,3 @@ export function createNodeClasses( : never; }; } - -@ObjectType() -export class PageInfo { - @Field(() => Boolean, { - name: "hasPreviousPage", - description: - "hasPreviousPage is used to indicate whether more edges exist prior to the set defined by the clients arguments. If the client is paginating with last/before, then the server must return true if prior edges exist, otherwise false. If the client is paginating with first/after, then the client may return true if edges prior to after exist, if it can do so efficiently, otherwise may return false.", - }) - hasPreviousPage!: boolean; - - @Field(() => Boolean, { - name: "hasNextPage", - description: - "hasNextPage is used to indicate whether more edges exist following the set defined by the clients arguments. If the client is paginating with first/after, then the server must return true if further edges exist, otherwise false. If the client is paginating with last/before, then the client may return true if edges further from before exist, if it can do so efficiently, otherwise may return false.", - }) - hasNextPage!: boolean; - - @Field(() => CursorScalar, { - name: "startCursor", - description: - "startCursor is simply an opaque value that refers to the first position in a connection. It is used by the client to request the first set of edges in a connection. The server must return the cursor that corresponds to the first element in the connection.", - }) - startCursor!: string; - - @Field(() => CursorScalar, { - name: "endCursor", - description: - "endCursor is simply an opaque value that refers to the last position in a connection. It is used by the client to request the last set of edges in a connection. The server must return the cursor that corresponds to the last element in the connection.", - }) - endCursor!: string; -} diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index 9028796d..6ee904d9 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -7,7 +7,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node] }) -export class DeviceResource extends TimestampedResource implements Node { +export class DeviceNode extends TimestampedResource implements Node { @Field(() => ID) uuid!: string; @@ -21,12 +21,12 @@ export class DeviceResource extends TimestampedResource implements Node { return this.uuid; } - public static init(init: Partial) { - return DeviceResource.doInit(init); + public static init(init: Partial) { + return DeviceNode.doInit(init); } } export const { DeviceConnection, DeviceEdge, DeviceResult } = createNodeClasses( - DeviceResource, + DeviceNode, "Device" ); diff --git a/packages/common/lib/api/resources/authorization.test.ts b/packages/common/lib/api/resources/authorization.test.ts index f7854c3f..2cd79f4e 100644 --- a/packages/common/lib/api/resources/authorization.test.ts +++ b/packages/common/lib/api/resources/authorization.test.ts @@ -9,69 +9,103 @@ import { DbRole, } from "../../index.js"; - const techChair: Authorization = { accessLevel: AccessLevel.Admin, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.techCommittee, - committeeRole: CommitteeRole.Chair, + committees: [ + { + identifier: CommitteeIdentifier.techCommittee, + role: CommitteeRole.Chair, + }, + ], }; const techCoordinator: Authorization = { accessLevel: AccessLevel.Admin, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.techCommittee, - committeeRole: CommitteeRole.Coordinator, + committees: [ + { + identifier: CommitteeIdentifier.techCommittee, + role: CommitteeRole.Coordinator, + }, + ], }; const techMember: Authorization = { accessLevel: AccessLevel.Admin, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.techCommittee, - committeeRole: CommitteeRole.Member, + committees: [ + { + identifier: CommitteeIdentifier.techCommittee, + role: CommitteeRole.Member, + }, + ], }; const overallChair: Authorization = { accessLevel: AccessLevel.CommitteeChairOrCoordinator, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.viceCommittee, - committeeRole: CommitteeRole.Chair, + committees: [ + { + identifier: CommitteeIdentifier.techCommittee, + role: CommitteeRole.Chair, + }, + { + identifier: CommitteeIdentifier.viceCommittee, + role: CommitteeRole.Chair, + }, + ], }; const dancerRelationsChair: Authorization = { accessLevel: AccessLevel.CommitteeChairOrCoordinator, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - committeeRole: CommitteeRole.Chair, + committees: [ + { + identifier: CommitteeIdentifier.dancerRelationsCommittee, + role: CommitteeRole.Chair, + }, + ], }; const dancerRelationsCoordinator: Authorization = { accessLevel: AccessLevel.CommitteeChairOrCoordinator, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - committeeRole: CommitteeRole.Coordinator, + committees: [ + { + identifier: CommitteeIdentifier.dancerRelationsCommittee, + role: CommitteeRole.Coordinator, + }, + ], }; const dancerRelationsMember: Authorization = { accessLevel: AccessLevel.Committee, dbRole: DbRole.Committee, - committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - committeeRole: CommitteeRole.Member, + committees: [ + { + identifier: CommitteeIdentifier.dancerRelationsCommittee, + role: CommitteeRole.Member, + }, + ], }; const member: Authorization = { accessLevel: AccessLevel.UKY, dbRole: DbRole.UKY, + committees: [], }; const publicAuth: Authorization = { accessLevel: AccessLevel.Public, dbRole: DbRole.Public, + committees: [], }; const none: Authorization = { accessLevel: AccessLevel.None, dbRole: DbRole.None, + committees: [], }; describe("checkAuthorization", () => { it("should return true when the user's access level matches the required access level", () => { @@ -163,7 +197,7 @@ describe("checkAuthorization", () => { return true; }, }, - { accessLevel: AccessLevel.None, dbRole: DbRole.None } + { accessLevel: AccessLevel.None, dbRole: DbRole.None, committees: [] } ) ).toBe(true); expect( @@ -173,7 +207,7 @@ describe("checkAuthorization", () => { return false; }, }, - { accessLevel: AccessLevel.None, dbRole: DbRole.None } + { accessLevel: AccessLevel.None, dbRole: DbRole.None, committees: [] } ) ).toBe(false); }); diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index b965c170..89ded32c 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,9 +1,8 @@ export { AuthIdPairResource as AuthIdPairNode } from "../types/AuthIdPair.js"; export { IntervalISO } from "../types/IntervalISO.js"; -export { Role as RoleResource, defaultRole } from "../types/Role.js"; export { ConfigurationNode } from "./Configuration.js"; -export { DeviceResource as DeviceNode } from "./Device.js"; +export { DeviceNode as DeviceNode } from "./Device.js"; export { EventResource as EventNode, EventOccurrenceResource as EventOccurrenceNode, diff --git a/packages/common/lib/api/types/Role.ts b/packages/common/lib/api/types/Role.ts deleted file mode 100644 index 2d5d90b1..00000000 --- a/packages/common/lib/api/types/Role.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Field, InputType, ObjectType } from "type-graphql"; - -import type { - AccessLevel, - Authorization, -} from "../../authorization/structures.js"; -import { - CommitteeIdentifier, - CommitteeRole, - DbRole, - defaultAuthorization, - isCommitteeIdentifier, -} from "../../authorization/structures.js"; -import { roleToAccessLevel, roleToAuthorization } from "../../index.js"; -import { Resource } from "../resources/Resource.js"; - -@InputType("RoleResourceInput") -@ObjectType() -export class Role extends Resource { - @Field(() => DbRole, { defaultValue: DbRole.None }) - dbRole!: DbRole; - @Field(() => CommitteeRole, { nullable: true }) - committeeRole!: CommitteeRole | null; - @Field(() => CommitteeIdentifier, { nullable: true }) - committeeIdentifier!: CommitteeIdentifier | null; - - public static init(init: Partial) { - return Role.doInit(init); - } - - static fromAuthorization(authorization: Readonly): Role { - const partial: Partial = {}; - partial.dbRole = authorization.dbRole; - partial.committeeRole = authorization.committeeRole ?? null; - if (isCommitteeIdentifier(authorization.committeeIdentifier)) { - partial.committeeIdentifier = authorization.committeeIdentifier; - } - - return this.init(partial); - } - - toAuthorization(): Authorization { - return roleToAuthorization(this); - } - - toAccessLevel(): AccessLevel { - return roleToAccessLevel(this); - } -} - -export const defaultRole = Role.fromAuthorization(defaultAuthorization); diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 26125cf9..87acaa5b 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -4,6 +4,7 @@ import type { AccessLevel, AuthSource, Authorization, + CommitteeIdentifier, CommitteeRole, DbRole, } from "../authorization/structures.js"; @@ -20,14 +21,17 @@ export function makeUserData( person: PersonResource, authSource: AuthSource, teamIds?: string[], - captainOfTeamIds?: string[] + captainOfTeamIds?: string[], + committees: { identifier: CommitteeIdentifier; role: CommitteeRole }[] = [] ): UserData { return { auth: { - dbRole: person.role.dbRole, - committeeRole: person.role.committeeRole ?? undefined, - committeeIdentifier: person.role.committeeIdentifier ?? undefined, - accessLevel: roleToAccessLevel(person.role), + dbRole: person.dbRole, + committees, + accessLevel: roleToAccessLevel({ + dbRole: person.dbRole, + committees, + }), }, userId: person.uuid, teamIds, diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index c6556e2e..41293f65 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -7,7 +7,7 @@ import type { Authorization, CommitteeRole, DbRole, - PersonResource, + PersonNode, UserData, } from "../index.js"; import { @@ -17,7 +17,11 @@ import { compareDbRole, } from "../index.js"; -export interface AuthorizationRule extends Partial { +export interface AuthorizationRule { + /** + * The minimum access level required to access this resource + */ + accessLevel?: AccessLevel; /** * Exact DanceBlue role, cannot be used with minDbRole */ @@ -57,18 +61,27 @@ export interface AuthorizationRule extends Partial { } export function checkAuthorization( - role: AuthorizationRule, + { + accessLevel, + committeeIdentifier, + committeeIdentifiers, + committeeRole, + custom, + dbRole, + minCommitteeRole, + minDbRole, + }: AuthorizationRule, authorization: Authorization ) { - if (role.minDbRole != null && role.dbRole != null) { + if (minDbRole != null && dbRole != null) { throw new TypeError(`Cannot specify both dbRole and minDbRole.`); } - if (role.minCommitteeRole != null && role.committeeRole != null) { + if (minCommitteeRole != null && committeeRole != null) { throw new TypeError( `Cannot specify both committeeRole and minCommitteeRole.` ); } - if (role.committeeIdentifier != null && role.committeeIdentifiers != null) { + if (committeeIdentifier != null && committeeIdentifiers != null) { throw new TypeError( `Cannot specify both committeeIdentifier and committeeIdentifiers.` ); @@ -77,47 +90,52 @@ export function checkAuthorization( let matches = true; // Access Level - if (role.accessLevel != null) { - matches &&= authorization.accessLevel >= role.accessLevel; + if (accessLevel != null) { + matches &&= authorization.accessLevel >= accessLevel; } // DB role - if (role.dbRole != null) { - matches &&= authorization.dbRole === role.dbRole; + if (dbRole != null) { + matches &&= authorization.dbRole === dbRole; } - if (role.minDbRole != null) { - matches &&= compareDbRole(authorization.dbRole, role.minDbRole) >= 0; + if (minDbRole != null) { + matches &&= compareDbRole(authorization.dbRole, minDbRole) >= 0; } // Committee role - if (role.committeeRole != null) { - matches &&= authorization.committeeRole === role.committeeRole; + if (committeeRole != null) { + matches &&= authorization.committees.some( + (committee) => + committee.role === committeeRole && + committee.identifier === committeeIdentifier + ); } - if (role.minCommitteeRole != null) { - if (authorization.committeeRole == null) { + if (minCommitteeRole != null) { + if (authorization.committees.length === 0) { matches = false; } else { - matches &&= - compareCommitteeRole( - authorization.committeeRole, - role.minCommitteeRole - ) >= 0; + matches &&= authorization.committees.some( + (committee) => + compareCommitteeRole(committee.role, minCommitteeRole) >= 0 + ); } } // Committee identifier(s) - if (role.committeeIdentifier != null) { - matches &&= authorization.committeeIdentifier === role.committeeIdentifier; + if (committeeIdentifier != null) { + matches &&= authorization.committees.some( + (committee) => committee.identifier === committeeIdentifier + ); } - if (role.committeeIdentifiers != null) { - matches &&= role.committeeIdentifiers.includes( - String(authorization.committeeIdentifier) + if (committeeIdentifiers != null) { + matches &&= authorization.committees.some((committee) => + committeeIdentifiers.includes(committee.identifier) ); } // Custom auth checker - if (role.custom != null) { - matches &&= role.custom(authorization); + if (custom != null) { + matches &&= custom(authorization); } return matches; } @@ -138,20 +156,20 @@ export interface AccessControlParam< argument: string | ((args: ArgsDictionary) => Primitive | Primitive[]); extractor: ( userData: UserData, - person: PersonResource | null + person: PersonNode | null ) => Primitive | Primitive[]; }[]; rootMatch?: { root: string | ((root: RootType) => Primitive | Primitive[]); extractor: ( userData: UserData, - person: PersonResource | null + person: PersonNode | null ) => Primitive | Primitive[]; }[]; } export interface AuthorizationContext { - authenticatedUser: PersonResource | null; + authenticatedUser: PersonNode | null; userData: UserData; } diff --git a/packages/common/lib/authorization/role.test.ts b/packages/common/lib/authorization/role.test.ts index b8178492..0efe187d 100644 --- a/packages/common/lib/authorization/role.test.ts +++ b/packages/common/lib/authorization/role.test.ts @@ -5,121 +5,82 @@ import { CommitteeIdentifier, CommitteeRole, DbRole, - RoleResource, } from "../index.js"; -import { roleToAccessLevel, roleToAuthorization } from "./role.js"; +import { roleToAccessLevel } from "./role.js"; describe("roleToAccessLevel", () => { it("returns the correct access level for a given role normally", () => { - const chairRole = RoleResource.init({ + const chairRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Chair, committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - }); + }; expect(roleToAccessLevel(chairRole)).toBe( AccessLevel.CommitteeChairOrCoordinator ); - const coordinatorRole = RoleResource.init({ + const coordinatorRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Coordinator, committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - }); + }; expect(roleToAccessLevel(coordinatorRole)).toBe( AccessLevel.CommitteeChairOrCoordinator ); - const memberRole = RoleResource.init({ + const memberRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Member, committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - }); + }; expect(roleToAccessLevel(memberRole)).toBe(AccessLevel.Committee); - const teamMemberRole = RoleResource.init({ + const teamMemberRole = { dbRole: DbRole.UKY, - }); + }; expect(roleToAccessLevel(teamMemberRole)).toBe(AccessLevel.UKY); - const publicRole = RoleResource.init({ + const publicRole = { dbRole: DbRole.Public, - }); + }; expect(roleToAccessLevel(publicRole)).toBe(AccessLevel.Public); - const noneRole = RoleResource.init({ + const noneRole = { dbRole: DbRole.None, - }); + }; expect(roleToAccessLevel(noneRole)).toBe(AccessLevel.None); }); it("grants any member of the tech committee admin access", () => { - const chairRole = RoleResource.init({ + const chairRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Chair, committeeIdentifier: CommitteeIdentifier.techCommittee, - }); + }; expect(roleToAccessLevel(chairRole)).toBe(AccessLevel.Admin); - const coordinatorRole = RoleResource.init({ + const coordinatorRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Coordinator, committeeIdentifier: CommitteeIdentifier.techCommittee, - }); + }; expect(roleToAccessLevel(coordinatorRole)).toBe(AccessLevel.Admin); - const memberRole = RoleResource.init({ + const memberRole = { dbRole: DbRole.Committee, committeeRole: CommitteeRole.Member, committeeIdentifier: CommitteeIdentifier.techCommittee, - }); + }; expect(roleToAccessLevel(memberRole)).toBe(AccessLevel.Admin); }); it("throws an error for an illegal role", () => { - const illegalRole = RoleResource.init({ + const illegalRole = { dbRole: "illegal" as DbRole, - }); + }; expect(() => roleToAccessLevel(illegalRole)).toThrow( "Illegal DbRole: [Parsing of 'illegal' failed]" ); }); }); - -describe("roleToAuthorization", () => { - it("converts a role to an authorization object", () => { - const role = RoleResource.init({ - dbRole: DbRole.UKY, - }); - expect(roleToAuthorization(role)).toStrictEqual({ - dbRole: DbRole.UKY, - accessLevel: AccessLevel.UKY, - }); - }); - - it("converts a role with a committee set to an authorization object", () => { - const role = RoleResource.init({ - dbRole: DbRole.Committee, - committeeRole: CommitteeRole.Member, - committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - }); - expect(roleToAuthorization(role)).toStrictEqual({ - dbRole: DbRole.Committee, - accessLevel: AccessLevel.Committee, - committeeRole: CommitteeRole.Member, - committeeIdentifier: CommitteeIdentifier.dancerRelationsCommittee, - }); - }); - - it("throws an error if one of committee or committeeRole is set without the other", ({ - expect, - }) => { - const role = RoleResource.init({ - dbRole: DbRole.Committee, - committeeRole: CommitteeRole.Chair, - }); - expect(() => roleToAuthorization(role)).toThrowError( - "Cannot have a committee role without a committee or vice versa" - ); - }); -}); diff --git a/packages/common/lib/authorization/role.ts b/packages/common/lib/authorization/role.ts index eada1d61..92c112fa 100644 --- a/packages/common/lib/authorization/role.ts +++ b/packages/common/lib/authorization/role.ts @@ -1,6 +1,3 @@ -import type { Role } from "../api/types/Role.js"; - -import type { Authorization } from "./structures.js"; import { AccessLevel, CommitteeIdentifier, @@ -8,6 +5,11 @@ import { DbRole, } from "./structures.js"; +export type Role = { + dbRole: DbRole; + committees?: { identifier: CommitteeIdentifier; role: CommitteeRole }[]; +}; + /** * Converts a DbRole to an AccessLevel * @@ -15,11 +17,7 @@ import { * @return The equivalent AccessLevel * @throws Error if the DbRole is not a valid member of the DbRole enum */ -export function roleToAccessLevel(role: { - dbRole: DbRole; - committeeRole?: CommitteeRole | null; - committeeIdentifier?: CommitteeIdentifier | null; -}): AccessLevel { +export function roleToAccessLevel(role: Role): AccessLevel { switch (role.dbRole) { case DbRole.None: { return AccessLevel.None; @@ -31,18 +29,32 @@ export function roleToAccessLevel(role: { return AccessLevel.UKY; } case DbRole.Committee: { - if (role.committeeIdentifier === CommitteeIdentifier.techCommittee) { - return AccessLevel.Admin; - } else if ( - role.committeeRole === CommitteeRole.Coordinator || - role.committeeRole === CommitteeRole.Chair - ) { - return AccessLevel.CommitteeChairOrCoordinator; - } else { - return AccessLevel.Committee; + let maxLevel: AccessLevel | null = null; + for (const committee of role.committees ?? []) { + let thisLevel: AccessLevel; + + if (committee.identifier === CommitteeIdentifier.techCommittee) { + thisLevel = AccessLevel.Admin; + } else if ( + committee.role === CommitteeRole.Coordinator || + committee.role === CommitteeRole.Chair + ) { + thisLevel = AccessLevel.CommitteeChairOrCoordinator; + } else { + thisLevel = AccessLevel.Committee; + } + + if (maxLevel === null || thisLevel > maxLevel) { + maxLevel = thisLevel; + } } + if (maxLevel === null) { + throw new Error("No committee roles found when DbRole was Committee"); + } + return maxLevel; } default: { + role.dbRole satisfies never; try { throw new Error(`Illegal DbRole: ${JSON.stringify(role.dbRole)}`); } catch (error) { @@ -53,28 +65,3 @@ export function roleToAccessLevel(role: { } } } - -/** - * Convert a RoleResource to an Authorization object - * - * @param role A full RoleResource object - * @return An Authorization object representing the same role - * @throws Error if one of committee or committeeRole is set without the other - */ -export function roleToAuthorization(role: Role): Authorization { - const auth: Authorization = { - dbRole: role.dbRole, - accessLevel: roleToAccessLevel(role), - }; - - if (role.committeeRole && role.committeeIdentifier) { - auth.committeeRole = role.committeeRole; - auth.committeeIdentifier = role.committeeIdentifier; - } else if (role.committeeIdentifier || role.committeeRole) { - throw new Error( - "Cannot have a committee role without a committee or vice versa" - ); - } - - return auth; -} diff --git a/packages/common/lib/authorization/structures.ts b/packages/common/lib/authorization/structures.ts index a248348c..991c8bd7 100644 --- a/packages/common/lib/authorization/structures.ts +++ b/packages/common/lib/authorization/structures.ts @@ -261,8 +261,10 @@ export const committeeNames: Record = { export interface Authorization { dbRole: DbRole; - committeeRole?: CommitteeRole; - committeeIdentifier?: string; + committees: { + identifier: CommitteeIdentifier; + role: CommitteeRole; + }[]; accessLevel: AccessLevel; } @@ -274,6 +276,7 @@ export interface Authorization { export const defaultAuthorization = { dbRole: DbRole.None, accessLevel: AccessLevel.None, + committees: [], } satisfies Authorization; // Registering the enum types with TypeGraphQL From f6201b43fe7015a3e3d5407f8052fb66505af73c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 24 Apr 2024 00:26:52 +0000 Subject: [PATCH 016/153] Update id field names in Node classes --- packages/common/lib/api/relay.ts | 2 +- packages/common/lib/api/resources/Configuration.ts | 2 +- packages/common/lib/api/resources/Device.ts | 4 ++-- packages/common/lib/api/resources/Event.ts | 4 ++-- packages/common/lib/api/resources/Feed.ts | 4 ++-- packages/common/lib/api/resources/Image.ts | 4 ++-- packages/common/lib/api/resources/Marathon.ts | 6 +++--- packages/common/lib/api/resources/MarathonHour.ts | 6 +++--- packages/common/lib/api/resources/Membership.ts | 4 ++-- packages/common/lib/api/resources/Notification.ts | 8 ++++---- packages/common/lib/api/resources/Person.ts | 6 +++--- packages/common/lib/api/resources/PointEntry.ts | 4 ++-- packages/common/lib/api/resources/PointOpportunity.ts | 4 ++-- packages/common/lib/api/resources/Team.ts | 4 ++-- packages/common/lib/authentication/jwt.ts | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index d4001fe9..4b61763a 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -37,7 +37,7 @@ export class PageInfo { @InterfaceType() export abstract class Node { @Field(() => ID) - uuid!: string; + id!: string; } @InterfaceType() export abstract class Edge { diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index b30b04d5..c1496c7c 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -22,7 +22,7 @@ to have additional validation logic in the future. }) export class ConfigurationNode extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) key!: string; diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index 6ee904d9..c25a55e3 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node] }) export class DeviceNode extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => DateTimeISOResolver, { nullable: true }) public lastLogin?: Date | null; @@ -18,7 +18,7 @@ export class DeviceNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index c8bde3ee..aa652629 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -10,7 +10,7 @@ import { Resource, TimestampedResource } from "./Resource.js"; }) export class EventResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => [EventOccurrenceResource]) occurrences!: EventOccurrenceResource[]; @Field(() => String) @@ -23,7 +23,7 @@ export class EventResource extends TimestampedResource implements Node { location!: string | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Feed.ts b/packages/common/lib/api/resources/Feed.ts index 23dc5c85..c6d2a914 100644 --- a/packages/common/lib/api/resources/Feed.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -19,7 +19,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class FeedResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @@ -28,7 +28,7 @@ export class FeedResource extends TimestampedResource implements Node { textContent?: string | null | undefined; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: { diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index 489e633a..b9ccdbd7 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class ImageResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => URLResolver, { nullable: true }) url!: URL | null; @@ -30,7 +30,7 @@ export class ImageResource extends TimestampedResource implements Node { height!: number; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index 6e65acf6..f366ac1a 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -11,7 +11,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class MarathonResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) year!: string; @Field(() => DateTimeISOResolver) @@ -26,7 +26,7 @@ export class MarathonResource extends TimestampedResource implements Node { } static init({ - uuid: id, + id: id, year, startDate, endDate, @@ -44,7 +44,7 @@ export class MarathonResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.uuid; + return this.id; } } diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index d6358d57..2706824a 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -11,7 +11,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class MarathonHourResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @Field(() => String, { nullable: true }) @@ -25,7 +25,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { durationInfo!: string; static init({ - uuid, + id: uuid, title, details, shownStartingAt, @@ -45,7 +45,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.uuid; + return this.id; } } diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index d7331237..9a524918 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -20,13 +20,13 @@ registerEnumType(MembershipPositionType, { }) export class MembershipResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => MembershipPositionType) position!: MembershipPositionType; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 106b5dd0..13f74262 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -16,7 +16,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class NotificationResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) title!: string; @@ -58,7 +58,7 @@ export class NotificationResource extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { @@ -77,7 +77,7 @@ export class NotificationDeliveryResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => Date, { nullable: true, @@ -111,7 +111,7 @@ export class NotificationDeliveryResource deliveryError?: string | null; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 8cfd1c6a..009f5b4b 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -10,7 +10,7 @@ import { TimestampedResource } from "./Resource.js"; }) export class PersonResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String, { nullable: true }) name!: string | null; @Field(() => String) @@ -21,7 +21,7 @@ export class PersonResource extends TimestampedResource implements Node { dbRole!: DbRole; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: { @@ -34,7 +34,7 @@ export class PersonResource extends TimestampedResource implements Node { updatedAt?: Date | null; }) { const resource = PersonResource.doInit({ - uuid: init.uuid, + id: init.uuid, email: init.email, }); diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index 03b8635b..407b6949 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -8,14 +8,14 @@ import { TimestampedResource } from "./Resource.js"; }) export class PointEntryResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String, { nullable: true }) comment!: string | null; @Field(() => Int) points!: number; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index 82390f02..d1c25cda 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -16,7 +16,7 @@ export class PointOpportunityResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) name!: string; @Field(() => TeamType) @@ -28,7 +28,7 @@ export class PointOpportunityResource } public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 22895803..fae7e765 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -35,7 +35,7 @@ registerEnumType(TeamLegacyStatus, { }) export class TeamResource extends TimestampedResource implements Node { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => String) name!: string; @Field(() => TeamType) @@ -44,7 +44,7 @@ export class TeamResource extends TimestampedResource implements Node { legacyStatus!: TeamLegacyStatus; public getUniqueId(): string { - return this.uuid; + return this.id; } public static init(init: Partial) { diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 87acaa5b..209bd7fc 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -33,7 +33,7 @@ export function makeUserData( committees, }), }, - userId: person.uuid, + userId: person.id, teamIds, captainOfTeamIds, authSource, From 2555c5b162c61cc963e0154313197b4637cb5571 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 24 Apr 2024 00:26:58 +0000 Subject: [PATCH 017/153] Add CommitteeNode class to common/lib/api/resources/Committee.ts --- packages/common/lib/api/resources/Committee.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/common/lib/api/resources/Committee.ts diff --git a/packages/common/lib/api/resources/Committee.ts b/packages/common/lib/api/resources/Committee.ts new file mode 100644 index 00000000..709d7408 --- /dev/null +++ b/packages/common/lib/api/resources/Committee.ts @@ -0,0 +1,15 @@ +import { Field, ID, ObjectType } from "type-graphql"; + +import { Node } from "../relay.js"; + +import { TimestampedResource } from "./Resource.js"; + +@ObjectType({ implements: [Node] }) +export class CommitteeNode extends TimestampedResource implements Node { + @Field(() => ID) + id!: string; + + public getUniqueId(): string { + return this.id; + } +} From e26ad9a06c206377fbe06a4967354521e89e2d45 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 24 Apr 2024 00:31:14 +0000 Subject: [PATCH 018/153] Refactor Node class names and update import paths --- packages/common/lib/api/resources/Event.ts | 18 +++---- packages/common/lib/api/resources/Feed.ts | 6 +-- packages/common/lib/api/resources/Image.ts | 8 +-- packages/common/lib/api/resources/Marathon.ts | 6 +-- .../common/lib/api/resources/MarathonHour.ts | 6 +-- .../common/lib/api/resources/Membership.ts | 8 +-- .../common/lib/api/resources/Notification.ts | 25 ++++------ packages/common/lib/api/resources/Team.ts | 8 +-- packages/common/lib/api/resources/index.ts | 50 ++++++++----------- 9 files changed, 62 insertions(+), 73 deletions(-) diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index aa652629..3ea33e84 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -8,11 +8,11 @@ import { Resource, TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class EventResource extends TimestampedResource implements Node { +export class EventNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; - @Field(() => [EventOccurrenceResource]) - occurrences!: EventOccurrenceResource[]; + @Field(() => [EventOccurrenceNode]) + occurrences!: EventOccurrenceNode[]; @Field(() => String) title!: string; @Field(() => String, { nullable: true }) @@ -26,15 +26,15 @@ export class EventResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return EventResource.doInit(init); + public static init(init: Partial) { + return EventNode.doInit(init); } } @ObjectType({ implements: [Resource], }) -export class EventOccurrenceResource extends Resource { +export class EventOccurrenceNode extends Resource { @Field(() => ID) uuid!: string; @Field(() => IntervalISO) @@ -46,12 +46,12 @@ export class EventOccurrenceResource extends Resource { return this.uuid; } - public static init(init: Partial) { - return EventOccurrenceResource.doInit(init); + public static init(init: Partial) { + return EventOccurrenceNode.doInit(init); } } export const { EventConnection, EventEdge, EventResult } = createNodeClasses( - EventResource, + EventNode, "Event" ); diff --git a/packages/common/lib/api/resources/Feed.ts b/packages/common/lib/api/resources/Feed.ts index c6d2a914..d3c2033d 100644 --- a/packages/common/lib/api/resources/Feed.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -17,7 +17,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class FeedResource extends TimestampedResource implements Node { +export class FeedNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -38,11 +38,11 @@ export class FeedResource extends TimestampedResource implements Node { createdAt?: Date; updatedAt?: Date; }) { - return FeedResource.doInit(init); + return FeedNode.doInit(init); } } export const { FeedConnection, FeedEdge, FeedResult } = createNodeClasses( - FeedResource, + FeedNode, "Feed" ); diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index b9ccdbd7..9d6b643a 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -7,7 +7,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class ImageResource extends TimestampedResource implements Node { +export class ImageNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -33,12 +33,12 @@ export class ImageResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return ImageResource.doInit(init); + public static init(init: Partial) { + return ImageNode.doInit(init); } } export const { ImageConnection, ImageEdge, ImageResult } = createNodeClasses( - ImageResource, + ImageNode, "Image" ); diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index f366ac1a..fd387e4a 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class MarathonResource extends TimestampedResource implements Node { +export class MarathonNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -32,7 +32,7 @@ export class MarathonResource extends TimestampedResource implements Node { endDate, createdAt, updatedAt, - }: Omit): MarathonResource { + }: Omit): MarathonNode { return this.doInit({ id, year, @@ -49,4 +49,4 @@ export class MarathonResource extends TimestampedResource implements Node { } export const { MarathonConnection, MarathonEdge, MarathonResult } = - createNodeClasses(MarathonResource, "Marathon"); + createNodeClasses(MarathonNode, "Marathon"); diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 2706824a..d18ad5eb 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class MarathonHourResource extends TimestampedResource implements Node { +export class MarathonHourNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -32,7 +32,7 @@ export class MarathonHourResource extends TimestampedResource implements Node { durationInfo, createdAt, updatedAt, - }: Omit): MarathonHourResource { + }: Omit): MarathonHourNode { return this.doInit({ uuid, title, @@ -50,4 +50,4 @@ export class MarathonHourResource extends TimestampedResource implements Node { } export const { MarathonHourConnection, MarathonHourEdge, MarathonHourResult } = - createNodeClasses(MarathonHourResource, "MarathonHour"); + createNodeClasses(MarathonHourNode, "MarathonHour"); diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index 9a524918..97e5cab8 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -18,7 +18,7 @@ registerEnumType(MembershipPositionType, { @ObjectType({ implements: [TimestampedResource, Node], }) -export class MembershipResource extends TimestampedResource implements Node { +export class MembershipNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -29,10 +29,10 @@ export class MembershipResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return MembershipResource.doInit(init); + public static init(init: Partial) { + return MembershipNode.doInit(init); } } export const { MembershipConnection, MembershipEdge, MembershipResult } = - createNodeClasses(MembershipResource, "Membership"); + createNodeClasses(MembershipNode, "Membership"); diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 13f74262..c3083605 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -3,18 +3,15 @@ import type { DateTime } from "luxon"; import { Field, ID, ObjectType } from "type-graphql"; import { AccessControl } from "../../authorization/accessControl.js"; -import { - AccessLevel, - createNodeClasses, - dateTimeFromSomething, -} from "../../index.js"; -import { Node } from "../relay.js"; +import { AccessLevel } from "../../authorization/structures.js"; +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; +import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class NotificationResource extends TimestampedResource implements Node { +export class NotificationNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @@ -61,18 +58,18 @@ export class NotificationResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return NotificationResource.doInit(init); + public static init(init: Partial) { + return NotificationNode.doInit(init); } } export const { NotificationConnection, NotificationEdge, NotificationResult } = - createNodeClasses(NotificationResource, "Notification"); + createNodeClasses(NotificationNode, "Notification"); @ObjectType({ implements: [TimestampedResource, Node], }) -export class NotificationDeliveryResource +export class NotificationDeliveryNode extends TimestampedResource implements Node { @@ -114,8 +111,8 @@ export class NotificationDeliveryResource return this.id; } - public static init(init: Partial) { - return NotificationDeliveryResource.doInit(init); + public static init(init: Partial) { + return NotificationDeliveryNode.doInit(init); } } @@ -123,4 +120,4 @@ export const { NotificationDeliveryConnection, NotificationDeliveryEdge, NotificationDeliveryResult, -} = createNodeClasses(NotificationDeliveryResource, "NotificationDelivery"); +} = createNodeClasses(NotificationDeliveryNode, "NotificationDelivery"); diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index fae7e765..465067e3 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -33,7 +33,7 @@ registerEnumType(TeamLegacyStatus, { @ObjectType({ implements: [TimestampedResource, Node], }) -export class TeamResource extends TimestampedResource implements Node { +export class TeamNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -47,12 +47,12 @@ export class TeamResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return TeamResource.doInit(init); + public static init(init: Partial) { + return TeamNode.doInit(init); } } export const { TeamConnection, TeamEdge, TeamResult } = createNodeClasses( - TeamResource, + TeamNode, "Team" ); diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index 89ded32c..c19e5a24 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,36 +1,28 @@ export { AuthIdPairResource as AuthIdPairNode } from "../types/AuthIdPair.js"; export { IntervalISO } from "../types/IntervalISO.js"; -export { ConfigurationNode } from "./Configuration.js"; -export { DeviceNode as DeviceNode } from "./Device.js"; -export { - EventResource as EventNode, - EventOccurrenceResource as EventOccurrenceNode, -} from "./Event.js"; -export { FeedResource as FeedNode } from "./Feed.js"; -export { ImageResource as ImageNode } from "./Image.js"; +export * from "./Committee.js"; +export * from "./Configuration.js"; +export * from "./Device.js"; +export * from "./Event.js"; +export * from "./Feed.js"; +export * from "./Image.js"; export * from "./Marathon.js"; export * from "./MarathonHour.js"; -export { - MembershipResource as MembershipNode, - MembershipPositionType, -} from "./Membership.js"; -export { - NotificationDeliveryResource as NotificationDeliveryNode, - NotificationResource as NotificationNode, -} from "./Notification.js"; -export { PersonResource as PersonNode } from "./Person.js"; -export { PointEntryResource as PointEntryNode } from "./PointEntry.js"; -export { PointOpportunityResource as PointOpportunityNode } from "./PointOpportunity.js"; -export { - Resource as Node, - TimestampedResource as TimestampedNode, -} from "./Resource.js"; -export { - TeamLegacyStatus, - TeamResource as TeamNode, - TeamType, -} from "./Team.js"; +export * from "./Membership.js"; +export * from "./Notification.js"; +export * from "./Person.js"; +export * from "./PointEntry.js"; +export * from "./PointOpportunity.js"; +export * from "./Resource.js"; +export * from "./Team.js"; -export * from "../relay.js"; +export { + Connection, + Edge, + Node, + PageInfo, + Resource, + Result, +} from "../relay.js"; export * from "../resourceError.js"; From 98fca04a505a48e72a91da5c66eefb06d050d94b Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 24 Apr 2024 00:32:08 +0000 Subject: [PATCH 019/153] Refactor PersonResource class to PersonNode and update import paths --- packages/common/lib/api/resources/Person.ts | 6 +++--- packages/common/lib/authentication/jwt.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 009f5b4b..41e6aaa1 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -8,7 +8,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [TimestampedResource, Node], }) -export class PersonResource extends TimestampedResource implements Node { +export class PersonNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String, { nullable: true }) @@ -33,7 +33,7 @@ export class PersonResource extends TimestampedResource implements Node { createdAt?: Date | null; updatedAt?: Date | null; }) { - const resource = PersonResource.doInit({ + const resource = PersonNode.doInit({ id: init.uuid, email: init.email, }); @@ -49,6 +49,6 @@ export class PersonResource extends TimestampedResource implements Node { } export const { PersonConnection, PersonEdge, PersonResult } = createNodeClasses( - PersonResource, + PersonNode, "Person" ); diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 209bd7fc..ab546290 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -1,4 +1,4 @@ -import type { PersonResource } from "../api/resources/Person.js"; +import type { PersonNode } from "../api/resources/Person.js"; import { roleToAccessLevel } from "../authorization/role.js"; import type { AccessLevel, @@ -18,7 +18,7 @@ export interface UserData { } export function makeUserData( - person: PersonResource, + person: PersonNode, authSource: AuthSource, teamIds?: string[], captainOfTeamIds?: string[], From 7340708c7f34b77a66fb1fffbaf5d550fd5eb33f Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 25 Apr 2024 00:24:08 +0000 Subject: [PATCH 020/153] Start on prisma stuff for marathon teams --- .../migration.sql | 32 +++++++++++++++++++ packages/server/prisma/schema.prisma | 10 +++--- 2 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql diff --git a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql new file mode 100644 index 00000000..ce002c7c --- /dev/null +++ b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql @@ -0,0 +1,32 @@ +/* + Warnings: + + - You are about to drop the column `marathon_year` on the `teams` table. All the data in the column will be lost. + - A unique constraint covering the columns `[marathon_id,persistent_identifier]` on the table `teams` will be added. If there are existing duplicate values, this will fail. + - Added the required column `marathon_id` to the `teams` table without a default value. This is not possible if the table is not empty. + +*/ + + + +-- AlterTable +WITH Db24Id AS ( + SELECT "id" + FROM "marathons" + WHERE "year" = "DB24" +) ALTER TABLE "teams" ADD COLUMN "marathon_id" INTEGER NOT NULL DEFAULT Db24Id; + +-- Remove the default value for the column `marathon_id` on the table `teams` +ALTER TABLE "teams" ALTER COLUMN "marathon_id" DROP DEFAULT; + +-- DropColumn +ALTER TABLE "teams" DROP COLUMN "marathon_year"; + +-- AddForeignKey +ALTER TABLE "teams" ADD CONSTRAINT "teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- DropIndex +DROP INDEX "teams_persistent_identifier_unique"; + +-- CreateIndex +CREATE UNIQUE INDEX "teams_marathon_id_persistent_identifier_key" ON "teams"("marathon_id", "persistent_identifier"); \ No newline at end of file diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 286c8e0d..0cbbe0e4 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -237,11 +237,13 @@ model Team { name String type TeamType legacyStatus TeamLegacyStatus @map("legacy_status") - marathonYear String @map("marathon_year") @db.Char(4) - persistentIdentifier String? @unique(map: "teams_persistent_identifier_unique") @map("persistent_identifier") + marathon Marathon @relation(fields: [marathonId], references: [id], onDelete: Cascade) + marathonId Int @map("marathon_id") + persistentIdentifier String? @map("persistent_identifier") memberships Membership[] pointEntries PointEntry[] + @@unique([marathonId, persistentIdentifier], map: "teams_marathon_id_persistent_identifier_key") @@index([uuid], map: "teams_uuid") @@map("teams") } @@ -253,7 +255,7 @@ view TeamsWithTotalPoints { type TeamType legacyStatus TeamLegacyStatus @map("legacystatus") persistentIdentifier String? @unique @map("persistentidentifier") - marathonYear String @map("marathonyear") @db.Char(4) + marathonId Int @map("marathonid") createdAt DateTime @map("createdat") @db.Timestamptz(6) updatedAt DateTime @map("updatedat") @db.Timestamptz(6) totalPoints BigInt @map("totalpoints") @@ -320,11 +322,11 @@ model Marathon { uuid String @unique(map: "marathons_uuid_unique") @default(uuid()) @db.Uuid createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - // Same format as Team.marathonYear year String @unique startDate DateTime @map("start_date") @db.Timestamptz(6) endDate DateTime @map("end_date") @db.Timestamptz(6) hours MarathonHour[] + teams Team[] @@index([uuid], map: "marathons_uuid") @@map("marathons") From ac59e107a9be10e891a9b287f170728ae3e69729 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:04:06 +0000 Subject: [PATCH 021/153] Resolve errors from device resolver --- .../device/deviceModelToResource.test.ts | 13 ++---- .../device/deviceModelToResource.ts | 12 ++--- .../notificationDeliveryModelToResource.ts | 6 +-- .../person/personModelToResource.ts | 12 ++--- .../src/resolvers/ConfigurationResolver.ts | 39 ++++++++-------- .../server/src/resolvers/DeviceResolver.ts | 46 +++++++++---------- 6 files changed, 58 insertions(+), 70 deletions(-) diff --git a/packages/server/src/repositories/device/deviceModelToResource.test.ts b/packages/server/src/repositories/device/deviceModelToResource.test.ts index 8122ec0b..4092eacc 100644 --- a/packages/server/src/repositories/device/deviceModelToResource.test.ts +++ b/packages/server/src/repositories/device/deviceModelToResource.test.ts @@ -1,6 +1,5 @@ import type { Device } from "@prisma/client"; -import { DeviceResource } from "@ukdanceblue/common"; -import { DateTime } from "luxon"; +import { DeviceNode } from "@ukdanceblue/common"; import { describe, expect, it } from "vitest"; import { deviceModelToResource } from "./deviceModelToResource.js"; @@ -20,12 +19,11 @@ describe("deviceModelToResource", () => { const resource = deviceModelToResource(deviceModel); - expect(resource).toBeInstanceOf(DeviceResource); + expect(resource).toBeInstanceOf(DeviceNode); expect(resource).toStrictEqual( - DeviceResource.init({ + DeviceNode.init({ uuid: "uuid", - expoPushToken: "token", - lastLogin: DateTime.fromISO("2021-01-01T00:00:00Z"), + lastLogin: new Date("2021-01-01T00:00:00Z"), createdAt: new Date("2021-01-01T00:00:00Z"), updatedAt: new Date("2021-01-01T00:00:00Z"), }) @@ -47,9 +45,8 @@ describe("deviceModelToResource", () => { const resource = deviceModelToResource(deviceModel); expect(resource).toStrictEqual( - DeviceResource.init({ + DeviceNode.init({ uuid: "uuid", - expoPushToken: "token", lastLogin: null, createdAt: new Date("2021-01-01T00:00:00Z"), updatedAt: new Date("2021-01-01T00:00:00Z"), diff --git a/packages/server/src/repositories/device/deviceModelToResource.ts b/packages/server/src/repositories/device/deviceModelToResource.ts index 4ac0aac8..9b53da9b 100644 --- a/packages/server/src/repositories/device/deviceModelToResource.ts +++ b/packages/server/src/repositories/device/deviceModelToResource.ts @@ -1,14 +1,10 @@ import type { Device } from "@prisma/client"; -import { DeviceResource } from "@ukdanceblue/common"; -import { DateTime } from "luxon"; +import { DeviceNode } from "@ukdanceblue/common"; -export function deviceModelToResource(deviceModel: Device): DeviceResource { - return DeviceResource.init({ +export function deviceModelToResource(deviceModel: Device): DeviceNode { + return DeviceNode.init({ uuid: deviceModel.uuid, - expoPushToken: deviceModel.expoPushToken, - lastLogin: deviceModel.lastSeen - ? DateTime.fromJSDate(deviceModel.lastSeen) - : null, + lastLogin: deviceModel.lastSeen, createdAt: deviceModel.createdAt, updatedAt: deviceModel.updatedAt, }); diff --git a/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts b/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts index d82e6961..3fa0cfe5 100644 --- a/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts +++ b/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts @@ -1,10 +1,10 @@ import type { NotificationDelivery } from "@prisma/client"; -import { NotificationDeliveryResource } from "@ukdanceblue/common"; +import { NotificationDeliveryNode } from "@ukdanceblue/common"; export function notificationDeliveryModelToResource( notificationDeliveryModel: NotificationDelivery -): NotificationDeliveryResource { - return NotificationDeliveryResource.init({ +): NotificationDeliveryNode { + return NotificationDeliveryNode.init({ uuid: notificationDeliveryModel.uuid, sentAt: notificationDeliveryModel.sentAt, receiptCheckedAt: notificationDeliveryModel.receiptCheckedAt, diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index e2df0096..c5845263 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -1,7 +1,7 @@ import type { Person } from "@prisma/client"; -import { DbRole, PersonResource, RoleResource } from "@ukdanceblue/common"; +import { DbRole, PersonNode } from "@ukdanceblue/common"; -export function personModelToResource(person: Person): PersonResource { +export function personModelToResource(person: Person): PersonNode { let dbRole: DbRole = DbRole.None; if (person.committeeRole) { dbRole = DbRole.Committee; @@ -11,16 +11,12 @@ export function personModelToResource(person: Person): PersonResource { dbRole = DbRole.Public; } - return PersonResource.init({ + return PersonNode.init({ uuid: person.uuid, name: person.name, email: person.email, linkblue: person.linkblue, - role: RoleResource.init({ - dbRole, - committeeRole: person.committeeRole, - committeeIdentifier: person.committeeName, - }), + dbRole, createdAt: person.createdAt, updatedAt: person.updatedAt, }); diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index 6f0991c9..70819ded 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -1,8 +1,7 @@ import { AccessControl, AccessLevel, - ConfigurationResource, - DateTimeScalar, + ConfigurationNode, DetailedError, ErrorCode, SortDirection, @@ -30,39 +29,39 @@ import { } from "./ApiResponse.js"; @ObjectType("GetConfigurationByUuidResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetConfigurationResponse extends AbstractGraphQLOkResponse { - @Field(() => ConfigurationResource) - data!: ConfigurationResource; +class GetConfigurationResponse extends AbstractGraphQLOkResponse { + @Field(() => ConfigurationNode) + data!: ConfigurationNode; } @ObjectType("GetAllConfigurationsResponse", { - implements: AbstractGraphQLArrayOkResponse, + implements: AbstractGraphQLArrayOkResponse, }) -class GetAllConfigurationsResponse extends AbstractGraphQLArrayOkResponse { - @Field(() => [ConfigurationResource]) - data!: ConfigurationResource[]; +class GetAllConfigurationsResponse extends AbstractGraphQLArrayOkResponse { + @Field(() => [ConfigurationNode]) + data!: ConfigurationNode[]; } @ObjectType("CreateConfigurationResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreateConfigurationResponse extends AbstractGraphQLCreatedResponse { - @Field(() => ConfigurationResource) - data!: ConfigurationResource; +class CreateConfigurationResponse extends AbstractGraphQLCreatedResponse { + @Field(() => ConfigurationNode) + data!: ConfigurationNode; } @ObjectType("CreateConfigurationsResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreateConfigurationsResponse extends AbstractGraphQLArrayOkResponse { - @Field(() => [ConfigurationResource]) - data!: ConfigurationResource[]; +class CreateConfigurationsResponse extends AbstractGraphQLArrayOkResponse { + @Field(() => [ConfigurationNode]) + data!: ConfigurationNode[]; } @ObjectType("DeleteConfigurationResponse", { implements: AbstractGraphQLOkResponse, }) class DeleteConfigurationResponse extends AbstractGraphQLOkResponse {} @InputType() -class CreateConfigurationInput implements Partial { +class CreateConfigurationInput implements Partial { @Field() key!: string; @@ -76,7 +75,7 @@ class CreateConfigurationInput implements Partial { validUntil!: DateTime | null; } -@Resolver(() => ConfigurationResource) +@Resolver(() => ConfigurationNode) @Service() export class ConfigurationResolver { constructor( diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 3f145e37..7788f201 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -1,10 +1,10 @@ import { DetailedError, - DeviceResource, + DeviceNode, ErrorCode, FilteredListQueryArgs, - NotificationDeliveryResource, - PersonResource, + NotificationDeliveryNode, + PersonNode, SortDirection, } from "@ukdanceblue/common"; import { @@ -35,25 +35,25 @@ import { } from "./ApiResponse.js"; @ObjectType("GetDeviceByUuidResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetDeviceByUuidResponse extends AbstractGraphQLOkResponse { - @Field(() => DeviceResource) - data!: DeviceResource; +class GetDeviceByUuidResponse extends AbstractGraphQLOkResponse { + @Field(() => DeviceNode) + data!: DeviceNode; } @ObjectType("ListDevicesResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListDevicesResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [DeviceResource]) - data!: DeviceResource[]; +class ListDevicesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [DeviceNode]) + data!: DeviceNode[]; } @ObjectType("RegisterDeviceResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class RegisterDeviceResponse extends AbstractGraphQLOkResponse { - @Field(() => DeviceResource) - data!: DeviceResource; +class RegisterDeviceResponse extends AbstractGraphQLOkResponse { + @Field(() => DeviceNode) + data!: DeviceNode; } @ObjectType("DeleteDeviceResponse", { implements: AbstractGraphQLOkResponse, @@ -61,7 +61,7 @@ class RegisterDeviceResponse extends AbstractGraphQLOkResponse { class DeleteDeviceResponse extends AbstractGraphQLOkResponse {} @InputType() -class RegisterDeviceInput implements Partial { +class RegisterDeviceInput { @Field(() => String) deviceId!: string; @@ -114,7 +114,7 @@ class NotificationDeliveriesArgs { pageSize?: number; } -@Resolver(() => DeviceResource) +@Resolver(() => DeviceNode) @Service() export class DeviceResolver { constructor(private deviceRepository: DeviceRepository) {} @@ -184,20 +184,20 @@ export class DeviceResolver { return DeleteDeviceResponse.newOk(true); } - @FieldResolver(() => PersonResource, { nullable: true }) + @FieldResolver(() => PersonNode, { nullable: true }) async lastLoggedInUser( - @Root() device: DeviceResource - ): Promise { + @Root() device: DeviceNode + ): Promise { const user = await this.deviceRepository.getLastLoggedInUser(device.uuid); return user == null ? null : personModelToResource(user); } - @FieldResolver(() => [NotificationDeliveryResource]) + @FieldResolver(() => [NotificationDeliveryNode]) async notificationDeliveries( - @Root() device: DeviceResource, + @Root() device: DeviceNode, @Args(() => NotificationDeliveriesArgs) query: NotificationDeliveriesArgs - ): Promise { + ): Promise { const row = await this.deviceRepository.getDeviceByUuid(device.uuid); if (row == null) { From 4869cfafd677a81df2b7d5e591a2969bdb6cd553 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:08:55 +0000 Subject: [PATCH 022/153] Replace references to renamed classes --- .../event/eventModelToResource.ts | 12 ++-- .../repositories/feed/feedModelToResource.ts | 6 +- .../image/imageModelToResource.ts | 6 +- .../membership/membershipModelToResource.ts | 10 +-- .../notificationModelToResource.ts | 6 +- .../pointEntry/pointEntryModelToResource.ts | 6 +- .../pointOpportunityModelToResource.ts | 6 +- .../repositories/team/teamModelToResource.ts | 6 +- .../server/src/resolvers/EventResolver.ts | 50 +++++++-------- packages/server/src/resolvers/FeedResolver.ts | 30 ++++----- .../server/src/resolvers/ImageResolver.ts | 34 +++++----- .../src/resolvers/MarathonHourResolver.ts | 4 +- .../src/resolvers/MembershipResolver.ts | 22 +++---- .../src/resolvers/NotificationResolver.ts | 50 +++++++-------- .../server/src/resolvers/PersonResolver.ts | 62 +++++++++---------- .../src/resolvers/PointEntryResolver.ts | 52 ++++++++-------- .../src/resolvers/PointOpportunityResolver.ts | 36 +++++------ packages/server/src/resolvers/TeamResolver.ts | 52 ++++++++-------- 18 files changed, 222 insertions(+), 228 deletions(-) diff --git a/packages/server/src/repositories/event/eventModelToResource.ts b/packages/server/src/repositories/event/eventModelToResource.ts index 13b1174c..29741de3 100644 --- a/packages/server/src/repositories/event/eventModelToResource.ts +++ b/packages/server/src/repositories/event/eventModelToResource.ts @@ -1,12 +1,12 @@ import type { Event, EventOccurrence } from "@prisma/client"; -import { EventOccurrenceResource, EventResource } from "@ukdanceblue/common"; +import { EventNode, EventOccurrenceNode } from "@ukdanceblue/common"; import { DateTime, Interval } from "luxon"; export function eventModelToResource( eventModel: Event, - occurrences: EventOccurrenceResource[] = [] -): EventResource { - return EventResource.init({ + occurrences: EventOccurrenceNode[] = [] +): EventNode { + return EventNode.init({ uuid: eventModel.uuid, title: eventModel.title, summary: eventModel.summary, @@ -20,8 +20,8 @@ export function eventModelToResource( export function eventOccurrenceModelToResource( occurrenceModel: EventOccurrence -): EventOccurrenceResource { - return EventOccurrenceResource.init({ +): EventOccurrenceNode { + return EventOccurrenceNode.init({ uuid: occurrenceModel.uuid, interval: Interval.fromDateTimes( DateTime.fromJSDate(occurrenceModel.date), diff --git a/packages/server/src/repositories/feed/feedModelToResource.ts b/packages/server/src/repositories/feed/feedModelToResource.ts index 2c3fadb0..3f39e820 100644 --- a/packages/server/src/repositories/feed/feedModelToResource.ts +++ b/packages/server/src/repositories/feed/feedModelToResource.ts @@ -1,8 +1,8 @@ import type { FeedItem } from "@prisma/client"; -import { FeedResource } from "@ukdanceblue/common"; +import { FeedNode } from "@ukdanceblue/common"; -export function feedItemModelToResource(feedItem: FeedItem): FeedResource { - return FeedResource.init({ +export function feedItemModelToResource(feedItem: FeedItem): FeedNode { + return FeedNode.init({ uuid: feedItem.uuid, title: feedItem.title, textContent: feedItem.textContent, diff --git a/packages/server/src/repositories/image/imageModelToResource.ts b/packages/server/src/repositories/image/imageModelToResource.ts index a8b56031..57ab640b 100644 --- a/packages/server/src/repositories/image/imageModelToResource.ts +++ b/packages/server/src/repositories/image/imageModelToResource.ts @@ -1,5 +1,5 @@ import type { File, Image } from "@prisma/client"; -import { ImageResource } from "@ukdanceblue/common"; +import { ImageNode } from "@ukdanceblue/common"; import type { FileManager } from "../../lib/files/FileManager.js"; import { combineMimePartsToString } from "../../lib/files/mime.js"; @@ -8,7 +8,7 @@ export async function imageModelToResource( imageModel: Image, fileModel: File | undefined | null, fileManager: FileManager -): Promise { +): Promise { let fileData: | { url: URL; @@ -30,7 +30,7 @@ export async function imageModelToResource( } } - return ImageResource.init({ + return ImageNode.init({ uuid: imageModel.uuid, url: fileData?.url ?? null, mimeType: fileData?.mimeType ?? "application/octet-stream", // "application/octet-stream" is the default MIME type if the file is not found diff --git a/packages/server/src/repositories/membership/membershipModelToResource.ts b/packages/server/src/repositories/membership/membershipModelToResource.ts index c87d19b0..f4c8c205 100644 --- a/packages/server/src/repositories/membership/membershipModelToResource.ts +++ b/packages/server/src/repositories/membership/membershipModelToResource.ts @@ -1,10 +1,10 @@ -import type { Membership } from "@prisma/client"; -import { MembershipResource } from "@ukdanceblue/common"; +import type { $1Node } from "@prisma/client"; +import { MembershipNode } from "@ukdanceblue/common"; export function membershipModelToResource( - membershipModel: Membership -): MembershipResource { - return MembershipResource.init({ + membershipModel: $1Node +): MembershipNode { + return MembershipNode.init({ uuid: membershipModel.uuid, position: membershipModel.position, createdAt: membershipModel.createdAt, diff --git a/packages/server/src/repositories/notification/notificationModelToResource.ts b/packages/server/src/repositories/notification/notificationModelToResource.ts index 411e6b39..5e693f4d 100644 --- a/packages/server/src/repositories/notification/notificationModelToResource.ts +++ b/packages/server/src/repositories/notification/notificationModelToResource.ts @@ -1,10 +1,10 @@ import type { Notification } from "@prisma/client"; -import { NotificationResource } from "@ukdanceblue/common"; +import { NotificationNode } from "@ukdanceblue/common"; export function notificationModelToResource( notificationModel: Notification -): NotificationResource { - return NotificationResource.init({ +): NotificationNode { + return NotificationNode.init({ uuid: notificationModel.uuid, title: notificationModel.title, body: notificationModel.body, diff --git a/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts b/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts index 7b161ce3..f953b10d 100644 --- a/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts +++ b/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts @@ -1,10 +1,10 @@ import type { PointEntry } from "@prisma/client"; -import { PointEntryResource } from "@ukdanceblue/common"; +import { PointEntryNode } from "@ukdanceblue/common"; export function pointEntryModelToResource( pointEntryModel: PointEntry -): PointEntryResource { - return PointEntryResource.init({ +): PointEntryNode { + return PointEntryNode.init({ uuid: pointEntryModel.uuid, points: pointEntryModel.points, comment: pointEntryModel.comment, diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts index 26808381..7fe3fa37 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts @@ -1,11 +1,11 @@ import type { PointOpportunity } from "@prisma/client"; -import { PointOpportunityResource } from "@ukdanceblue/common"; +import { PointOpportunityNode } from "@ukdanceblue/common"; import { DateTime } from "luxon"; export function pointOpportunityModelToResource( pointOpportunityModel: PointOpportunity -): PointOpportunityResource { - return PointOpportunityResource.init({ +): PointOpportunityNode { + return PointOpportunityNode.init({ uuid: pointOpportunityModel.uuid, name: pointOpportunityModel.name, type: pointOpportunityModel.type, diff --git a/packages/server/src/repositories/team/teamModelToResource.ts b/packages/server/src/repositories/team/teamModelToResource.ts index 0cbba275..f920414f 100644 --- a/packages/server/src/repositories/team/teamModelToResource.ts +++ b/packages/server/src/repositories/team/teamModelToResource.ts @@ -1,14 +1,14 @@ import type { Team } from "@prisma/client"; -import { TeamResource } from "@ukdanceblue/common"; +import { TeamNode } from "@ukdanceblue/common"; const marathonYearRegex = /^DB\d{2}$/; -export function teamModelToResource(teamModel: Team): TeamResource { +export function teamModelToResource(teamModel: Team): TeamNode { if (!marathonYearRegex.test(teamModel.marathonYear)) { throw new Error(`Invalid marathon year: ${teamModel.marathonYear}`); } - return TeamResource.init({ + return TeamNode.init({ uuid: teamModel.uuid, name: teamModel.name, persistentIdentifier: teamModel.persistentIdentifier, diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index c089184f..3035cc5d 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -5,9 +5,9 @@ import { DateRangeScalar, DetailedError, ErrorCode, - EventResource, + EventNode, FilteredListQueryArgs, - ImageResource, + ImageNode, SortDirection, } from "@ukdanceblue/common"; import { Interval } from "luxon"; @@ -43,25 +43,25 @@ import { } from "./ApiResponse.js"; @ObjectType("GetEventByUuidResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetEventByUuidResponse extends AbstractGraphQLOkResponse { - @Field(() => EventResource) - data!: EventResource; +class GetEventByUuidResponse extends AbstractGraphQLOkResponse { + @Field(() => EventNode) + data!: EventNode; } @ObjectType("CreateEventResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreateEventResponse extends AbstractGraphQLCreatedResponse { - @Field(() => EventResource) - data!: EventResource; +class CreateEventResponse extends AbstractGraphQLCreatedResponse { + @Field(() => EventNode) + data!: EventNode; } @ObjectType("SetEventResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class SetEventResponse extends AbstractGraphQLOkResponse { - @Field(() => EventResource) - data!: EventResource; +class SetEventResponse extends AbstractGraphQLOkResponse { + @Field(() => EventNode) + data!: EventNode; } @ObjectType("DeleteEventResponse", { implements: AbstractGraphQLOkResponse, @@ -77,19 +77,19 @@ class RemoveEventImageResponse extends AbstractGraphQLOkResponse { } @ObjectType("AddEventImageResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class AddEventImageResponse extends AbstractGraphQLOkResponse { - @Field(() => ImageResource) - data!: ImageResource; +class AddEventImageResponse extends AbstractGraphQLOkResponse { + @Field(() => ImageNode) + data!: ImageNode; } @ObjectType("ListEventsResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListEventsResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [EventResource]) - data!: EventResource[]; +class ListEventsResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [EventNode]) + data!: EventNode[]; } @InputType() @@ -193,7 +193,7 @@ class ListEventsArgs extends FilteredListQueryArgs< }) {} @Service() -@Resolver(() => EventResource) +@Resolver(() => EventNode) export class EventResolver { constructor( private readonly eventRepository: EventRepository, @@ -394,8 +394,8 @@ export class EventResolver { ); } - @FieldResolver(() => [ImageResource]) - async images(@Root() event: EventResource): Promise { + @FieldResolver(() => [ImageNode]) + async images(@Root() event: EventNode): Promise { const rows = await this.eventImageRepository.findEventImagesByEventUnique({ uuid: event.uuid, }); diff --git a/packages/server/src/resolvers/FeedResolver.ts b/packages/server/src/resolvers/FeedResolver.ts index d40f6988..d8ed74fd 100644 --- a/packages/server/src/resolvers/FeedResolver.ts +++ b/packages/server/src/resolvers/FeedResolver.ts @@ -1,8 +1,8 @@ import { DetailedError, ErrorCode, - FeedResource, - ImageResource, + FeedNode, + ImageNode, } from "@ukdanceblue/common"; import { Arg, @@ -40,7 +40,7 @@ export class SetFeedInput { textContent?: string | null | undefined; } -@Resolver(() => FeedResource) +@Resolver(() => FeedNode) @Service() export class FeedResolver { constructor( @@ -48,19 +48,19 @@ export class FeedResolver { private readonly fileManager: FileManager ) {} - @Query(() => [FeedResource]) + @Query(() => [FeedNode]) async feed( @Arg("limit", () => Int, { defaultValue: 10, nullable: true }) limit: number | null - ): Promise { + ): Promise { const rows = await this.feedRepository.getCompleteFeed({ limit }); return rows.map(feedItemModelToResource); } - @Mutation(() => FeedResource) + @Mutation(() => FeedNode) async createFeedItem( @Arg("input") input: CreateFeedInput - ): Promise { + ): Promise { const feedItem = await this.feedRepository.createFeedItem({ title: input.title, textContent: input.textContent, @@ -69,11 +69,11 @@ export class FeedResolver { return feedItemModelToResource(feedItem); } - @Mutation(() => FeedResource) + @Mutation(() => FeedNode) async attachImageToFeedItem( @Arg("feedItemUuid") feedItemUuid: string, @Arg("imageUuid") imageUuid: string - ): Promise { + ): Promise { const feedItem = await this.feedRepository.attachImageToFeedItem( { uuid: feedItemUuid, @@ -88,10 +88,10 @@ export class FeedResolver { return feedItemModelToResource(feedItem); } - @Mutation(() => FeedResource) + @Mutation(() => FeedNode) async removeImageFromFeedItem( @Arg("feedItemUuid") feedItemUuid: string - ): Promise { + ): Promise { const feedItem = await this.feedRepository.removeImageFromFeedItem({ uuid: feedItemUuid, }); @@ -101,11 +101,11 @@ export class FeedResolver { return feedItemModelToResource(feedItem); } - @Mutation(() => FeedResource) + @Mutation(() => FeedNode) async setFeedItem( @Arg("feedItemUuid") feedItemUuid: string, @Arg("input") input: SetFeedInput - ): Promise { + ): Promise { const feedItem = await this.feedRepository.updateFeedItem( { uuid: feedItemUuid }, { @@ -129,8 +129,8 @@ export class FeedResolver { return feedItem != null; } - @FieldResolver(() => ImageResource, { nullable: true }) - async image(@Root() { uuid }: FeedResource) { + @FieldResolver(() => ImageNode, { nullable: true }) + async image(@Root() { uuid }: FeedNode) { const row = await this.feedRepository.getFeedItemImage({ uuid }); if (row == null) { return null; diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index f7c60d68..62461703 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -6,7 +6,7 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - ImageResource, + ImageNode, SortDirection, } from "@ukdanceblue/common"; import { URLResolver } from "graphql-scalars"; @@ -37,9 +37,9 @@ import { } from "./ApiResponse.js"; @ObjectType("GetImageByUuidResponse", { implements: AbstractGraphQLOkResponse }) -class GetImageByUuidResponse extends AbstractGraphQLOkResponse { - @Field(() => ImageResource) - data!: ImageResource; +class GetImageByUuidResponse extends AbstractGraphQLOkResponse { + @Field(() => ImageNode) + data!: ImageNode; } @ObjectType("DeleteImageResponse", { @@ -47,7 +47,7 @@ class GetImageByUuidResponse extends AbstractGraphQLOkResponse { }) class DeleteImageResponse extends AbstractGraphQLOkResponse {} @InputType() -class CreateImageInput implements Partial { +class CreateImageInput implements Partial { @Field(() => String, { nullable: true }) alt?: string | null; @@ -71,14 +71,14 @@ class ListImagesArgs extends FilteredListQueryArgs< }) {} @ObjectType("ListImagesResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListImagesResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [ImageResource]) - data!: ImageResource[]; +class ListImagesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [ImageNode]) + data!: ImageNode[]; } -@Resolver(() => ImageResource) +@Resolver(() => ImageNode) @Service() export class ImageResolver { constructor( @@ -133,8 +133,8 @@ export class ImageResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => ImageResource, { name: "createImage" }) - async create(@Arg("input") input: CreateImageInput): Promise { + @Mutation(() => ImageNode, { name: "createImage" }) + async create(@Arg("input") input: CreateImageInput): Promise { const { mime, thumbHash, width, height } = await handleImageUrl(input.url); const result = await this.imageRepository.createImage({ width, @@ -173,11 +173,11 @@ export class ImageResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => ImageResource, { name: "setImageAltText" }) + @Mutation(() => ImageNode, { name: "setImageAltText" }) async setAltText( @Arg("uuid") uuid: string, @Arg("alt") alt: string - ): Promise { + ): Promise { const result = await this.imageRepository.updateImage( { uuid, @@ -197,11 +197,11 @@ export class ImageResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => ImageResource, { name: "setImageUrl" }) + @Mutation(() => ImageNode, { name: "setImageUrl" }) async setImageUrl( @Arg("uuid") uuid: string, @Arg("url", () => URLResolver) url: URL - ): Promise { + ): Promise { const { mime, thumbHash, width, height } = await handleImageUrl(url); const result = await this.imageRepository.updateImage( { @@ -240,7 +240,7 @@ export class ImageResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => ImageResource, { name: "setImageUrl" }) + @Mutation(() => ImageNode, { name: "setImageUrl" }) @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => DeleteImageResponse, { name: "deleteImage" }) async delete(@Arg("uuid") uuid: string): Promise { diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index 72a30cf5..0cbd2e63 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -2,7 +2,7 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - ImageResource, + ImageNode, MarathonHourResource, } from "@ukdanceblue/common"; import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; @@ -135,7 +135,7 @@ export class MarathonHourResolver { }); } - @FieldResolver(() => [ImageResource]) + @FieldResolver(() => [ImageNode]) async mapImages(@Root() marathonHour: MarathonHourResource) { return this.marathonHourRepository.getMaps({ uuid: marathonHour.uuid }); } diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index b48df25d..38f5d060 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -1,9 +1,9 @@ import { DetailedError, ErrorCode, - MembershipResource, - PersonResource, - TeamResource, + MembershipNode, + PersonNode, + TeamNode, } from "@ukdanceblue/common"; import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; @@ -12,15 +12,13 @@ import { MembershipRepository } from "../repositories/membership/MembershipRepos import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; -@Resolver(() => MembershipResource) +@Resolver(() => MembershipNode) @Service() export class MembershipResolver { constructor(private readonly membershipRepository: MembershipRepository) {} - @FieldResolver(() => PersonResource) - async person( - @Root() membership: MembershipResource - ): Promise { + @FieldResolver(() => PersonNode) + async person(@Root() membership: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( { uuid: membership.uuid }, { @@ -29,14 +27,14 @@ export class MembershipResolver { ); if (row == null) { - throw new DetailedError(ErrorCode.NotFound, "Membership not found"); + throw new DetailedError(ErrorCode.NotFound, "$1Node not found"); } return personModelToResource(row.person); } - @FieldResolver(() => TeamResource) - async team(@Root() membership: MembershipResource): Promise { + @FieldResolver(() => TeamNode) + async team(@Root() membership: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( { uuid: membership.uuid }, { @@ -45,7 +43,7 @@ export class MembershipResolver { ); if (row == null) { - throw new DetailedError(ErrorCode.NotFound, "Membership not found"); + throw new DetailedError(ErrorCode.NotFound, "$1Node not found"); } return teamModelToResource(row.team); diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 52f33a09..47d00d58 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -5,8 +5,8 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - NotificationDeliveryResource, - NotificationResource, + NotificationDeliveryNode, + NotificationNode, SortDirection, TeamType, } from "@ukdanceblue/common"; @@ -41,18 +41,18 @@ import { } from "./ApiResponse.js"; @ObjectType("GetNotificationByUuidResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetNotificationByUuidResponse extends AbstractGraphQLOkResponse { - @Field(() => NotificationResource) - data!: NotificationResource; +class GetNotificationByUuidResponse extends AbstractGraphQLOkResponse { + @Field(() => NotificationNode) + data!: NotificationNode; } @ObjectType("ListNotificationsResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListNotificationsResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [NotificationResource]) - data!: NotificationResource[]; +class ListNotificationsResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [NotificationNode]) + data!: NotificationNode[]; } @InputType() @@ -86,11 +86,11 @@ class StageNotificationArgs { } @ObjectType("StageNotificationResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class StageNotificationResponse extends AbstractGraphQLCreatedResponse { - @Field(() => NotificationResource) - data!: NotificationResource; +class StageNotificationResponse extends AbstractGraphQLCreatedResponse { + @Field(() => NotificationNode) + data!: NotificationNode; } @ObjectType("SendNotificationResponse", { @@ -186,11 +186,11 @@ class ListNotificationDeliveriesArgs extends FilteredListQueryArgs< } @ObjectType("ListNotificationDeliveriesResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListNotificationDeliveriesResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [NotificationDeliveryResource]) - data!: NotificationDeliveryResource[]; +class ListNotificationDeliveriesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [NotificationDeliveryNode]) + data!: NotificationDeliveryNode[]; } @ObjectType("NotificationDeliveryIssueCount", { @@ -214,7 +214,7 @@ class NotificationDeliveryIssueCount Unknown!: number; } -@Resolver(() => NotificationResource) +@Resolver(() => NotificationNode) @Service() export class NotificationResolver { constructor( @@ -532,7 +532,7 @@ export class NotificationResolver { accessLevel: AccessLevel.CommitteeChairOrCoordinator, }) @FieldResolver(() => Int, { name: "deliveryCount" }) - async deliveryCount(@Root() { uuid }: NotificationResource): Promise { + async deliveryCount(@Root() { uuid }: NotificationNode): Promise { return this.notificationRepository.countDeliveriesForNotification({ uuid }); } @@ -543,7 +543,7 @@ export class NotificationResolver { name: "deliveryIssueCount", }) async deliveryIssueCount( - @Root() { uuid }: NotificationResource + @Root() { uuid }: NotificationNode ): Promise { const issues = await this.notificationRepository.countFailedDeliveriesForNotification({ @@ -557,19 +557,19 @@ export class NotificationResolver { } } -@Resolver(() => NotificationDeliveryResource) +@Resolver(() => NotificationDeliveryNode) @Service() export class NotificationDeliveryResolver { constructor( private readonly notificationDeliveryRepository: NotificationDeliveryRepository ) {} - @FieldResolver(() => NotificationResource, { + @FieldResolver(() => NotificationNode, { name: "notification", }) async getNotificationForDelivery( - @Root() { uuid }: NotificationDeliveryResource - ): Promise { + @Root() { uuid }: NotificationDeliveryNode + ): Promise { const notification = await this.notificationDeliveryRepository.findNotificationForDelivery({ uuid, diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index a560d75e..9e934417 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -4,9 +4,9 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, + MembershipNode, MembershipPositionType, - MembershipResource, - PersonResource, + PersonNode, RoleResource, SortDirection, } from "@ukdanceblue/common"; @@ -41,32 +41,32 @@ import { import * as Context from "./context.js"; @ObjectType("CreatePersonResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreatePersonResponse extends AbstractGraphQLCreatedResponse { - @Field(() => PersonResource) - data!: PersonResource; +class CreatePersonResponse extends AbstractGraphQLCreatedResponse { + @Field(() => PersonNode) + data!: PersonNode; } @ObjectType("GetPersonResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetPersonResponse extends AbstractGraphQLOkResponse { - @Field(() => PersonResource, { nullable: true }) - data!: PersonResource | null; +class GetPersonResponse extends AbstractGraphQLOkResponse { + @Field(() => PersonNode, { nullable: true }) + data!: PersonNode | null; } @ObjectType("GetPeopleResponse", { - implements: AbstractGraphQLArrayOkResponse, + implements: AbstractGraphQLArrayOkResponse, }) -class GetPeopleResponse extends AbstractGraphQLArrayOkResponse { - @Field(() => [PersonResource]) - data!: PersonResource[]; +class GetPeopleResponse extends AbstractGraphQLArrayOkResponse { + @Field(() => [PersonNode]) + data!: PersonNode[]; } @ObjectType("ListPeopleResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListPeopleResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [PersonResource]) - data!: PersonResource[]; +class ListPeopleResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [PersonNode]) + data!: PersonNode[]; } @ObjectType("DeletePersonResponse", { implements: AbstractGraphQLOkResponse, @@ -134,7 +134,7 @@ class SetPersonInput { captainOf?: string[]; } -@Resolver(() => PersonResource) +@Resolver(() => PersonNode) @Service() export class PersonResolver { constructor(private personRepository: PersonRepository) {} @@ -144,12 +144,12 @@ export class PersonResolver { const row = await this.personRepository.findPersonByUuid(uuid); if (row == null) { - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( null ); } - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( personModelToResource(row) ); } @@ -162,12 +162,12 @@ export class PersonResolver { const row = await this.personRepository.findPersonByLinkblue(linkBlueId); if (row == null) { - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( null ); } - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( personModelToResource(row) ); } @@ -204,7 +204,7 @@ export class PersonResolver { @Query(() => GetPersonResponse, { name: "me" }) me(@Ctx() ctx: Context.GraphQLContext): GetPersonResponse | null { - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( ctx.authenticatedUser ); } @@ -259,12 +259,12 @@ export class PersonResolver { ); if (row == null) { - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( null ); } - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( personModelToResource(row) ); } @@ -300,8 +300,8 @@ export class PersonResolver { ], } ) - @FieldResolver(() => [MembershipResource]) - async teams(@Root() person: PersonResource): Promise { + @FieldResolver(() => [MembershipNode]) + async teams(@Root() person: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson({ uuid: person.uuid, }); @@ -314,12 +314,10 @@ export class PersonResolver { } @AccessControl({ accessLevel: AccessLevel.Committee }) - @FieldResolver(() => [MembershipResource], { + @FieldResolver(() => [MembershipNode], { deprecationReason: "Use teams instead and filter by position", }) - async captaincies( - @Root() person: PersonResource - ): Promise { + async captaincies(@Root() person: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson( { uuid: person.uuid }, { position: MembershipPositionType.Captain } diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 0bb00088..4599d581 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -2,11 +2,11 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - PersonResource, - PointEntryResource, - PointOpportunityResource, + PersonNode, + PointEntryNode, + PointOpportunityNode, SortDirection, - TeamResource, + TeamNode, } from "@ukdanceblue/common"; import { Arg, @@ -37,25 +37,25 @@ import { } from "./ApiResponse.js"; @ObjectType("GetPointEntryByUuidResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class GetPointEntryByUuidResponse extends AbstractGraphQLOkResponse { - @Field(() => PointEntryResource) - data!: PointEntryResource; +class GetPointEntryByUuidResponse extends AbstractGraphQLOkResponse { + @Field(() => PointEntryNode) + data!: PointEntryNode; } @ObjectType("ListPointEntriesResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListPointEntriesResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [PointEntryResource]) - data!: PointEntryResource[]; +class ListPointEntriesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [PointEntryNode]) + data!: PointEntryNode[]; } @ObjectType("CreatePointEntryResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreatePointEntryResponse extends AbstractGraphQLCreatedResponse { - @Field(() => PointEntryResource) - data!: PointEntryResource; +class CreatePointEntryResponse extends AbstractGraphQLCreatedResponse { + @Field(() => PointEntryNode) + data!: PointEntryNode; } @ObjectType("DeletePointEntryResponse", { implements: AbstractGraphQLOkResponse, @@ -63,7 +63,7 @@ class CreatePointEntryResponse extends AbstractGraphQLCreatedResponse {} @InputType() -class CreatePointEntryInput implements Partial { +class CreatePointEntryInput implements Partial { @Field(() => String, { nullable: true }) comment!: string | null; @@ -93,7 +93,7 @@ class ListPointEntriesArgs extends FilteredListQueryArgs< date: ["createdAt", "updatedAt"], }) {} -@Resolver(() => PointEntryResource) +@Resolver(() => PointEntryNode) @Service() export class PointEntryResolver { constructor(private readonly pointEntryRepository: PointEntryRepository) {} @@ -170,10 +170,10 @@ export class PointEntryResolver { return DeletePointEntryResponse.newOk(true); } - @FieldResolver(() => PersonResource, { nullable: true }) + @FieldResolver(() => PersonNode, { nullable: true }) async personFrom( - @Root() pointEntry: PointEntryResource - ): Promise { + @Root() pointEntry: PointEntryNode + ): Promise { const model = await this.pointEntryRepository.getPointEntryPersonFrom({ uuid: pointEntry.uuid, }); @@ -181,8 +181,8 @@ export class PointEntryResolver { return model ? personModelToResource(model) : null; } - @FieldResolver(() => TeamResource) - async team(@Root() pointEntry: PointEntryResource): Promise { + @FieldResolver(() => TeamNode) + async team(@Root() pointEntry: PointEntryNode): Promise { const model = await this.pointEntryRepository.getPointEntryTeam({ uuid: pointEntry.uuid, }); @@ -194,10 +194,10 @@ export class PointEntryResolver { return teamModelToResource(model); } - @FieldResolver(() => PointOpportunityResource, { nullable: true }) + @FieldResolver(() => PointOpportunityNode, { nullable: true }) async pointOpportunity( - @Root() pointEntry: PointEntryResource - ): Promise { + @Root() pointEntry: PointEntryNode + ): Promise { const model = await this.pointEntryRepository.getPointEntryOpportunity({ uuid: pointEntry.uuid, }); diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index 62aa91c0..3645d6e9 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -2,9 +2,9 @@ import { DateTimeScalar, DetailedError, ErrorCode, - EventResource, + EventNode, FilteredListQueryArgs, - PointOpportunityResource, + PointOpportunityNode, SortDirection, TeamType, } from "@ukdanceblue/common"; @@ -36,25 +36,25 @@ import { } from "./ApiResponse.js"; @ObjectType("SinglePointOpportunityResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class SinglePointOpportunityResponse extends AbstractGraphQLOkResponse { - @Field(() => PointOpportunityResource) - data!: PointOpportunityResource; +class SinglePointOpportunityResponse extends AbstractGraphQLOkResponse { + @Field(() => PointOpportunityNode) + data!: PointOpportunityNode; } @ObjectType("ListPointOpportunitiesResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListPointOpportunitiesResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [PointOpportunityResource]) - data!: PointOpportunityResource[]; +class ListPointOpportunitiesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [PointOpportunityNode]) + data!: PointOpportunityNode[]; } @ObjectType("CreatePointOpportunityResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreatePointOpportunityResponse extends AbstractGraphQLCreatedResponse { - @Field(() => PointOpportunityResource) - data!: PointOpportunityResource; +class CreatePointOpportunityResponse extends AbstractGraphQLCreatedResponse { + @Field(() => PointOpportunityNode) + data!: PointOpportunityNode; } @ObjectType("DeletePointOpportunityResponse", { implements: AbstractGraphQLOkResponse, @@ -106,7 +106,7 @@ class ListPointOpportunitiesArgs extends FilteredListQueryArgs< date: ["opportunityDate", "createdAt", "updatedAt"], }) {} -@Resolver(() => PointOpportunityResource) +@Resolver(() => PointOpportunityNode) @Service() export class PointOpportunityResolver { constructor( @@ -223,10 +223,10 @@ export class PointOpportunityResolver { return DeletePointOpportunityResponse.newOk(true); } - @FieldResolver(() => EventResource, { nullable: true }) + @FieldResolver(() => EventNode, { nullable: true }) async event( - @Root() pointOpportunity: PointOpportunityResource - ): Promise { + @Root() pointOpportunity: PointOpportunityNode + ): Promise { const model = await this.pointOpportunityRepository.getEventForPointOpportunity({ uuid: pointOpportunity.uuid, diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 96ec229d..1f142c80 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -12,11 +12,11 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - MembershipResource, - PointEntryResource, + MembershipNode, + PointEntryNode, SortDirection, TeamLegacyStatus, - TeamResource, + TeamNode, TeamType, } from "@ukdanceblue/common"; import { @@ -49,25 +49,25 @@ import { import * as Context from "./context.js"; @ObjectType("SingleTeamResponse", { - implements: AbstractGraphQLOkResponse, + implements: AbstractGraphQLOkResponse, }) -class SingleTeamResponse extends AbstractGraphQLOkResponse { - @Field(() => TeamResource) - data!: TeamResource; +class SingleTeamResponse extends AbstractGraphQLOkResponse { + @Field(() => TeamNode) + data!: TeamNode; } @ObjectType("ListTeamsResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListTeamsResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [TeamResource]) - data!: TeamResource[]; +class ListTeamsResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [TeamNode]) + data!: TeamNode[]; } @ObjectType("CreateTeamResponse", { - implements: AbstractGraphQLCreatedResponse, + implements: AbstractGraphQLCreatedResponse, }) -class CreateTeamResponse extends AbstractGraphQLCreatedResponse { - @Field(() => TeamResource) - data!: TeamResource; +class CreateTeamResponse extends AbstractGraphQLCreatedResponse { + @Field(() => TeamNode) + data!: TeamNode; } @ObjectType("DeleteTeamResponse", { implements: AbstractGraphQLOkResponse, @@ -75,7 +75,7 @@ class CreateTeamResponse extends AbstractGraphQLCreatedResponse { class DeleteTeamResponse extends AbstractGraphQLOkResponse {} @InputType() -class CreateTeamInput implements OptionalToNullable> { +class CreateTeamInput implements OptionalToNullable> { @Field(() => String) name!: string; @@ -93,7 +93,7 @@ class CreateTeamInput implements OptionalToNullable> { } @InputType() -class SetTeamInput implements OptionalToNullable> { +class SetTeamInput implements OptionalToNullable> { @Field(() => String, { nullable: true }) name!: string | null; @@ -137,7 +137,7 @@ class ListTeamsArgs extends FilteredListQueryArgs< marathonYear!: [MarathonYearString] | null; } -@Resolver(() => TeamResource) +@Resolver(() => TeamNode) @Service() export class TeamResolver { constructor(private teamRepository: TeamRepository) {} @@ -310,8 +310,8 @@ export class TeamResolver { ], } ) - @FieldResolver(() => [MembershipResource]) - async members(@Root() team: TeamResource): Promise { + @FieldResolver(() => [MembershipNode]) + async members(@Root() team: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam({ uuid: team.uuid, }); @@ -320,10 +320,10 @@ export class TeamResolver { } @AccessControl({ accessLevel: AccessLevel.Committee }) - @FieldResolver(() => [MembershipResource], { + @FieldResolver(() => [MembershipNode], { deprecationReason: "Just query the members field and filter by role", }) - async captains(@Root() team: TeamResource): Promise { + async captains(@Root() team: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam( { uuid: team.uuid }, { captainsOnly: true } @@ -343,10 +343,8 @@ export class TeamResolver { ], } ) - @FieldResolver(() => [PointEntryResource]) - async pointEntries( - @Root() team: TeamResource - ): Promise { + @FieldResolver(() => [PointEntryNode]) + async pointEntries(@Root() team: TeamNode): Promise { const rows = await this.teamRepository.getTeamPointEntries({ uuid: team.uuid, }); @@ -356,7 +354,7 @@ export class TeamResolver { @AccessControl({ accessLevel: AccessLevel.Public }) @FieldResolver(() => Int) - async totalPoints(@Root() team: TeamResource): Promise { + async totalPoints(@Root() team: TeamNode): Promise { const result = await this.teamRepository.getTotalTeamPoints({ uuid: team.uuid, }); From d403acdcc0de2db280bf79d7e1ece1b2b21d6b1d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:13:50 +0000 Subject: [PATCH 023/153] Refactor import paths and remove unused code --- packages/common/lib/api/resources/Marathon.ts | 9 ++++++++- .../common/lib/api/resources/MarathonHour.ts | 10 +++++++++- packages/common/lib/api/types/IntervalISO.ts | 19 +++++++++++++++++-- .../configurationModelToResource.ts | 15 ++++++++------- .../event/eventModelToResource.ts | 12 ++++++------ .../marathon/marathonModelToResource.ts | 4 ++-- .../marathonHourModelToResource.ts | 2 +- .../membership/membershipModelToResource.ts | 3 +-- .../repositories/person/PersonRepository.ts | 2 -- .../pointOpportunityModelToResource.ts | 5 +---- .../repositories/team/teamModelToResource.ts | 2 -- 11 files changed, 53 insertions(+), 30 deletions(-) diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index fd387e4a..f63751ac 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -32,7 +32,14 @@ export class MarathonNode extends TimestampedResource implements Node { endDate, createdAt, updatedAt, - }: Omit): MarathonNode { + }: { + id: string; + year: string; + startDate: Date; + endDate: Date; + createdAt?: Date | null; + updatedAt?: Date | null; + }): MarathonNode { return this.doInit({ id, year, diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index d18ad5eb..e116ac6a 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -32,7 +32,15 @@ export class MarathonHourNode extends TimestampedResource implements Node { durationInfo, createdAt, updatedAt, - }: Omit): MarathonHourNode { + }: { + id: string; + title: string; + details?: string | null; + shownStartingAt: Date; + durationInfo: string; + createdAt?: Date | null; + updatedAt?: Date | null; + }): MarathonHourNode { return this.doInit({ uuid, title, diff --git a/packages/common/lib/api/types/IntervalISO.ts b/packages/common/lib/api/types/IntervalISO.ts index ee866c23..cd59b098 100644 --- a/packages/common/lib/api/types/IntervalISO.ts +++ b/packages/common/lib/api/types/IntervalISO.ts @@ -7,13 +7,13 @@ import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; @ObjectType() export class IntervalISO { @Field(() => DateTimeISOResolver) - readonly start!: Date; + start!: Date; get startDateTime(): DateTime { return dateTimeFromSomething(this.start); } @Field(() => DateTimeISOResolver) - readonly end!: Date; + end!: Date; get endDateTime(): DateTime { return dateTimeFromSomething(this.end); } @@ -36,4 +36,19 @@ export class IntervalISO { isEmpty(): boolean { return this.interval.isEmpty(); } + + static init(start: Date, end: Date): IntervalISO { + const self = new IntervalISO(); + self.start = start; + self.end = end; + return self; + } + + static fromDateTimes(start: DateTime, end: DateTime): IntervalISO { + return this.init(start.toJSDate(), end.toJSDate()); + } + + static fromInterval(interval: Interval): IntervalISO { + return this.fromDateTimes(interval.start, interval.end); + } } diff --git a/packages/server/src/repositories/configuration/configurationModelToResource.ts b/packages/server/src/repositories/configuration/configurationModelToResource.ts index ae936d0a..130b7b99 100644 --- a/packages/server/src/repositories/configuration/configurationModelToResource.ts +++ b/packages/server/src/repositories/configuration/configurationModelToResource.ts @@ -1,15 +1,16 @@ import type { Configuration } from "@prisma/client"; -import { ConfigurationResource } from "@ukdanceblue/common"; -import { DateTime } from "luxon"; +import { ConfigurationNode } from "@ukdanceblue/common"; -export function configurationModelToResource(configuration: Configuration): ConfigurationResource { - return ConfigurationResource.init({ +export function configurationModelToResource( + configuration: Configuration +): ConfigurationNode { + return ConfigurationNode.init({ uuid: configuration.uuid, key: configuration.key, value: configuration.value, - validAfter: configuration.validAfter ? DateTime.fromJSDate(configuration.validAfter) : null, - validUntil: configuration.validUntil ? DateTime.fromJSDate(configuration.validUntil) : null, + validAfter: configuration.validAfter, + validUntil: configuration.validUntil, createdAt: configuration.createdAt, updatedAt: configuration.updatedAt, }); -} \ No newline at end of file +} diff --git a/packages/server/src/repositories/event/eventModelToResource.ts b/packages/server/src/repositories/event/eventModelToResource.ts index 29741de3..f5e903a6 100644 --- a/packages/server/src/repositories/event/eventModelToResource.ts +++ b/packages/server/src/repositories/event/eventModelToResource.ts @@ -1,6 +1,9 @@ import type { Event, EventOccurrence } from "@prisma/client"; -import { EventNode, EventOccurrenceNode } from "@ukdanceblue/common"; -import { DateTime, Interval } from "luxon"; +import { + EventNode, + EventOccurrenceNode, + IntervalISO, +} from "@ukdanceblue/common"; export function eventModelToResource( eventModel: Event, @@ -23,10 +26,7 @@ export function eventOccurrenceModelToResource( ): EventOccurrenceNode { return EventOccurrenceNode.init({ uuid: occurrenceModel.uuid, - interval: Interval.fromDateTimes( - DateTime.fromJSDate(occurrenceModel.date), - DateTime.fromJSDate(occurrenceModel.endDate) - ), + interval: IntervalISO.init(occurrenceModel.date, occurrenceModel.endDate), fullDay: occurrenceModel.fullDay, }); } diff --git a/packages/server/src/repositories/marathon/marathonModelToResource.ts b/packages/server/src/repositories/marathon/marathonModelToResource.ts index 409a9d4b..88ce43d0 100644 --- a/packages/server/src/repositories/marathon/marathonModelToResource.ts +++ b/packages/server/src/repositories/marathon/marathonModelToResource.ts @@ -7,8 +7,8 @@ export function marathonModelToResource( return MarathonResource.init({ uuid: marathonModel.uuid, year: marathonModel.year, - startDate: marathonModel.startDate.toISOString(), - endDate: marathonModel.endDate.toISOString(), + startDate: marathonModel.startDate, + endDate: marathonModel.endDate, createdAt: marathonModel.createdAt, updatedAt: marathonModel.updatedAt, }); diff --git a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts index 6e749575..a6d14a80 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts @@ -9,7 +9,7 @@ export function marathonHourModelToResource( title: marathonHourModel.title, details: marathonHourModel.details, durationInfo: marathonHourModel.durationInfo, - shownStartingAt: marathonHourModel.shownStartingAt.toISOString(), + shownStartingAt: marathonHourModel.shownStartingAt, createdAt: marathonHourModel.createdAt, updatedAt: marathonHourModel.updatedAt, }); diff --git a/packages/server/src/repositories/membership/membershipModelToResource.ts b/packages/server/src/repositories/membership/membershipModelToResource.ts index f4c8c205..c1423a9a 100644 --- a/packages/server/src/repositories/membership/membershipModelToResource.ts +++ b/packages/server/src/repositories/membership/membershipModelToResource.ts @@ -1,8 +1,7 @@ -import type { $1Node } from "@prisma/client"; import { MembershipNode } from "@ukdanceblue/common"; export function membershipModelToResource( - membershipModel: $1Node + membershipModel: MembershipNode ): MembershipNode { return MembershipNode.init({ uuid: membershipModel.uuid, diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 82e7a1ea..80aac8d8 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -1,10 +1,8 @@ import type { Person } from "@prisma/client"; import { AuthSource, Prisma, PrismaClient } from "@prisma/client"; import type { - AuthIdPairResource, CommitteeIdentifier, CommitteeRole, - RoleResource, SortDirection, } from "@ukdanceblue/common"; import { MembershipPositionType, TeamLegacyStatus } from "@ukdanceblue/common"; diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts index 7fe3fa37..d0ac731d 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts @@ -1,6 +1,5 @@ import type { PointOpportunity } from "@prisma/client"; import { PointOpportunityNode } from "@ukdanceblue/common"; -import { DateTime } from "luxon"; export function pointOpportunityModelToResource( pointOpportunityModel: PointOpportunity @@ -9,9 +8,7 @@ export function pointOpportunityModelToResource( uuid: pointOpportunityModel.uuid, name: pointOpportunityModel.name, type: pointOpportunityModel.type, - opportunityDate: pointOpportunityModel.opportunityDate - ? DateTime.fromJSDate(pointOpportunityModel.opportunityDate) - : undefined, + opportunityDate: pointOpportunityModel.opportunityDate, createdAt: pointOpportunityModel.createdAt, updatedAt: pointOpportunityModel.updatedAt, }); diff --git a/packages/server/src/repositories/team/teamModelToResource.ts b/packages/server/src/repositories/team/teamModelToResource.ts index f920414f..8104dbf9 100644 --- a/packages/server/src/repositories/team/teamModelToResource.ts +++ b/packages/server/src/repositories/team/teamModelToResource.ts @@ -11,10 +11,8 @@ export function teamModelToResource(teamModel: Team): TeamNode { return TeamNode.init({ uuid: teamModel.uuid, name: teamModel.name, - persistentIdentifier: teamModel.persistentIdentifier, type: teamModel.type, legacyStatus: teamModel.legacyStatus, - marathonYear: teamModel.marathonYear as `DB${number}`, createdAt: teamModel.createdAt, updatedAt: teamModel.updatedAt, }); From d5126561d266051a62f880d6639a0cd994d97132 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:14:13 +0000 Subject: [PATCH 024/153] Update auth login functions to include empty committees array --- packages/server/src/routes/api/auth/anonymous.ts | 1 + packages/server/src/routes/api/auth/demo.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/server/src/routes/api/auth/anonymous.ts b/packages/server/src/routes/api/auth/anonymous.ts index 84cd02ec..b8304af7 100644 --- a/packages/server/src/routes/api/auth/anonymous.ts +++ b/packages/server/src/routes/api/auth/anonymous.ts @@ -30,6 +30,7 @@ export const anonymousLogin = (ctx: Context) => { auth: { accessLevel: AccessLevel.Public, dbRole: DbRole.Public, + committees: [], }, authSource: AuthSource.Anonymous, }); diff --git a/packages/server/src/routes/api/auth/demo.ts b/packages/server/src/routes/api/auth/demo.ts index c33022e0..708ec98e 100644 --- a/packages/server/src/routes/api/auth/demo.ts +++ b/packages/server/src/routes/api/auth/demo.ts @@ -38,6 +38,7 @@ export const demoLogin = async (ctx: Context) => { auth: { accessLevel: AccessLevel.UKY, dbRole: DbRole.UKY, + committees: [], }, userId: person.uuid, teamIds: person.memberships.map((m) => m.team.uuid), From c6bdcc7cd0795237b207c4f2f8907429d99258b0 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:19:43 +0000 Subject: [PATCH 025/153] Refactor import paths and update auth login functions --- .../server/src/lib/auth/findPersonForLogin.ts | 10 ++------- .../repositories/person/PersonRepository.ts | 21 ++++++++----------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/server/src/lib/auth/findPersonForLogin.ts b/packages/server/src/lib/auth/findPersonForLogin.ts index 990b6c71..887c6637 100644 --- a/packages/server/src/lib/auth/findPersonForLogin.ts +++ b/packages/server/src/lib/auth/findPersonForLogin.ts @@ -1,5 +1,5 @@ import type { AuthSource, Prisma, PrismaClient } from "@prisma/client"; -import type { RoleResource } from "@ukdanceblue/common"; +import type { UserData } from "@ukdanceblue/common"; import { MembershipPositionType } from "@ukdanceblue/common"; import { logger } from "../logging/logger.js"; @@ -29,13 +29,7 @@ const include = { export async function findPersonForLogin( client: PrismaClient, authIds: [AuthSource, string][], - userData: { - uuid?: string | null; - email?: string | null; - linkblue?: string | null; - name?: string | null; - role?: RoleResource | null; - }, + userData: UserData, memberOf?: (string | number)[], captainOf?: (string | number)[] ) { diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 80aac8d8..1501d12e 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -1,11 +1,14 @@ import type { Person } from "@prisma/client"; -import { AuthSource, Prisma, PrismaClient } from "@prisma/client"; -import type { +import { Prisma, PrismaClient } from "@prisma/client"; +import { + AuthSource, CommitteeIdentifier, CommitteeRole, + MembershipPositionType, SortDirection, + TeamLegacyStatus, + UserData, } from "@ukdanceblue/common"; -import { MembershipPositionType, TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; @@ -48,14 +51,8 @@ export class PersonRepository { // Finders findPersonForLogin( - authIds: [AuthSource, string][], - userData: { - uuid?: string | null; - email?: string | null; - linkblue?: string | null; - name?: string | null; - role?: RoleResource | null; - }, + authIds: [Exclude, string][], + userData: UserData, memberOf?: (string | number)[], captainOf?: (string | number)[] ) { @@ -205,7 +202,7 @@ export class PersonRepository { linkblue?: string | null; committeeRole?: CommitteeRole | null; committeeName?: CommitteeIdentifier | null; - authIds?: AuthIdPairResource>[] | null; + authIds?: { source: Exclude; value: string }[] | null; }): Promise { return this.prisma.person.create({ data: { From cb80cc496cb47b9e8c7e39ffa88e687ce5f37e10 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:30:38 +0000 Subject: [PATCH 026/153] Refactor import paths and update auth login functions --- packages/common/lib/authentication/jwt.ts | 3 +- .../server/src/lib/auth/findPersonForLogin.ts | 34 +++--- packages/server/src/lib/auth/index.ts | 110 +++++------------- packages/server/src/lib/auth/role.ts | 1 - .../repositories/person/PersonRepository.ts | 12 +- 5 files changed, 61 insertions(+), 99 deletions(-) delete mode 100644 packages/server/src/lib/auth/role.ts diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index ab546290..d3ddcb0b 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -46,8 +46,7 @@ export interface JwtPayload { auth_source: AuthSource; // TODO: Replace these fields with either "roles" or "groups" (these are specified in the RFC 7643 Section 4.1.2) dbRole: DbRole; - committee_role?: CommitteeRole; - committee?: string; + committees?: { role: CommitteeRole; identifier: CommitteeIdentifier }[]; access_level: AccessLevel; team_ids?: string[]; captain_of_team_ids?: string[]; diff --git a/packages/server/src/lib/auth/findPersonForLogin.ts b/packages/server/src/lib/auth/findPersonForLogin.ts index 887c6637..5467da43 100644 --- a/packages/server/src/lib/auth/findPersonForLogin.ts +++ b/packages/server/src/lib/auth/findPersonForLogin.ts @@ -1,5 +1,5 @@ import type { AuthSource, Prisma, PrismaClient } from "@prisma/client"; -import type { UserData } from "@ukdanceblue/common"; +import type { DbRole } from "@ukdanceblue/common"; import { MembershipPositionType } from "@ukdanceblue/common"; import { logger } from "../logging/logger.js"; @@ -24,12 +24,18 @@ const include = { * Searches the database for a user with the given auth IDs or user data, or creates a new user if none is found * * @param authIds The auth IDs to search for - * @param userData The user data to fall back on if no user is found with the given auth IDs + * @param userInfo The user data to fall back on if no user is found with the given auth IDs */ export async function findPersonForLogin( client: PrismaClient, authIds: [AuthSource, string][], - userData: UserData, + userInfo: { + uuid?: string | null; + email?: string | null; + linkblue?: string | null; + name?: string | null; + dbRole?: DbRole | null; + }, memberOf?: (string | number)[], captainOf?: (string | number)[] ) { @@ -39,9 +45,9 @@ export async function findPersonForLogin( let created = false; // If we have a UUID, search for an existing person with that UUID - if (userData.uuid) { + if (userInfo.uuid) { currentPerson = await client.person.findUnique({ - where: { uuid: userData.uuid }, + where: { uuid: userInfo.uuid }, include, }); if (currentPerson) { @@ -66,18 +72,18 @@ export async function findPersonForLogin( } // Search for an existing person with the given unique user data - if (!currentPerson && userData.linkblue) { + if (!currentPerson && userInfo.linkblue) { currentPerson = await client.person.findUnique({ - where: { linkblue: userData.linkblue }, + where: { linkblue: userInfo.linkblue }, include, }); if (currentPerson) { logger.trace(`Found person by linkblue: ${currentPerson.uuid}`); } } - if (!currentPerson && userData.email) { + if (!currentPerson && userInfo.email) { currentPerson = await client.person.findUnique({ - where: { email: userData.email }, + where: { email: userInfo.email }, include, }); if (currentPerson) { @@ -87,7 +93,7 @@ export async function findPersonForLogin( if (!currentPerson) { logger.trace("No person found, creating new person"); - if (!userData.email) { + if (!userInfo.email) { throw new Error("No email provided for new user"); } // currentPerson = PersonModel.build({ @@ -153,11 +159,9 @@ export async function findPersonForLogin( })), }, }, - email: userData.email, - name: userData.name ?? null, - linkblue: userData.linkblue ?? null, - committeeRole: userData.role?.committeeRole ?? null, - committeeName: userData.role?.committeeIdentifier ?? null, + email: userInfo.email, + name: userInfo.name ?? null, + linkblue: userInfo.linkblue ?? null, memberships: { createMany: { data: [ diff --git a/packages/server/src/lib/auth/index.ts b/packages/server/src/lib/auth/index.ts index 6d80d7d6..f0ec07d5 100644 --- a/packages/server/src/lib/auth/index.ts +++ b/packages/server/src/lib/auth/index.ts @@ -1,70 +1,15 @@ -import type { Authorization, JwtPayload, UserData } from "@ukdanceblue/common"; +import type { JwtPayload, UserData } from "@ukdanceblue/common"; import { AccessLevel, AuthSource, CommitteeRole, DbRole, - defaultAuthorization, } from "@ukdanceblue/common"; import type { Request } from "express"; import jsonwebtoken from "jsonwebtoken"; import { jwtSecret } from "../../environment.js"; -/** - * Compares an authorization object to a minimum authorization object - * and returns true if the authorization object satisfies the minimum - * authorization object (i.e. the authorization object has at least - * the same authorization as the minimum authorization object) - * - * @param minAuth The minimum authorization object - * @param auth The authorization object to compare to the minimum authorization object - * @return True if the authorization object satisfies the minimum authorization object - * and false otherwise - */ -export function isMinAuthSatisfied( - minAuth: Authorization, - auth: Authorization -): boolean { - if (auth.accessLevel < minAuth.accessLevel) { - return false; - } - if (minAuth.committeeRole && auth.committeeRole !== minAuth.committeeRole) { - return false; - } - if ( - minAuth.committeeIdentifier && - auth.committeeIdentifier !== minAuth.committeeIdentifier - ) { - return false; - } - return true; -} - -export const simpleAuthorizations: Record = { - [AccessLevel.None]: defaultAuthorization, - [AccessLevel.Public]: { - dbRole: DbRole.Public, - accessLevel: AccessLevel.Public, - }, - [AccessLevel.UKY]: { - dbRole: DbRole.UKY, - accessLevel: AccessLevel.UKY, - }, - [AccessLevel.Committee]: { - dbRole: DbRole.Committee, - accessLevel: AccessLevel.Committee, - }, - [AccessLevel.CommitteeChairOrCoordinator]: { - dbRole: DbRole.Committee, - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - [AccessLevel.Admin]: { - dbRole: DbRole.Committee, - accessLevel: AccessLevel.Admin, - }, -}; - const jwtIssuer = "https://app.danceblue.org"; /** @@ -79,8 +24,7 @@ export function isValidJwtPayload(payload: unknown): payload is JwtPayload { sub, auth_source, dbRole, - committee_role, - committee, + committees, access_level, team_ids, captain_of_team_ids, @@ -101,15 +45,33 @@ export function isValidJwtPayload(payload: unknown): payload is JwtPayload { ) { return false; } - if ( - committee_role !== undefined && - (typeof committee_role !== "string" || - !Object.values(CommitteeRole).includes(committee_role as CommitteeRole)) - ) { - return false; - } - if (committee !== undefined && typeof committee !== "string") { - return false; + // if ( + // committee_role !== undefined && + // (typeof committee_role !== "string" || + // !Object.values(CommitteeRole).includes(committee_role as CommitteeRole)) + // ) { + // return false; + // } + // if (committee !== undefined && typeof committee !== "string") { + // return false; + // } + if (committees) { + if (!Array.isArray(committees)) { + return false; + } + for (const committee of committees as unknown[]) { + if ( + typeof committee !== "object" || + committee === null || + typeof (committee as { role?: unknown }).role !== "string" || + !Object.values(CommitteeRole).includes( + (committee as { role?: unknown }).role as CommitteeRole + ) || + typeof (committee as { identifier?: unknown }).identifier !== "string" + ) { + return false; + } + } } if ( typeof access_level !== "number" || @@ -150,11 +112,8 @@ export function makeUserJwt(user: UserData): string { if (user.userId) { payload.sub = user.userId; } - if (user.auth.committeeRole) { - payload.committee_role = user.auth.committeeRole; - } - if (user.auth.committeeIdentifier) { - payload.committee = user.auth.committeeIdentifier; + if (user.auth.committees.length > 0) { + payload.committees = user.auth.committees; } if (user.teamIds) { payload.team_ids = user.teamIds; @@ -201,6 +160,7 @@ export function parseUserJwt(token: string): UserData { auth: { accessLevel: payload.access_level, dbRole: payload.dbRole, + committees: payload.committees || [], }, authSource: payload.auth_source, }; @@ -208,12 +168,6 @@ export function parseUserJwt(token: string): UserData { if (payload.sub) { userData.userId = payload.sub; } - if (payload.committee_role) { - userData.auth.committeeRole = payload.committee_role; - } - if (payload.committee) { - userData.auth.committeeIdentifier = payload.committee; - } if (payload.team_ids) { userData.teamIds = payload.team_ids; } diff --git a/packages/server/src/lib/auth/role.ts b/packages/server/src/lib/auth/role.ts deleted file mode 100644 index 45a59a18..00000000 --- a/packages/server/src/lib/auth/role.ts +++ /dev/null @@ -1 +0,0 @@ -export { roleToAccessLevel, roleToAuthorization } from "@ukdanceblue/common"; diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 1501d12e..855d5354 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -4,10 +4,10 @@ import { AuthSource, CommitteeIdentifier, CommitteeRole, + DbRole, MembershipPositionType, SortDirection, TeamLegacyStatus, - UserData, } from "@ukdanceblue/common"; import { Service } from "typedi"; @@ -52,14 +52,20 @@ export class PersonRepository { findPersonForLogin( authIds: [Exclude, string][], - userData: UserData, + userInfo: { + uuid?: string | null; + email?: string | null; + linkblue?: string | null; + name?: string | null; + dbRole?: DbRole | null; + }, memberOf?: (string | number)[], captainOf?: (string | number)[] ) { return findPersonForLogin( this.prisma, authIds, - userData, + userInfo, memberOf, captainOf ); From 9f0714a8110eb0b07406831a935144d9b2d7e4f1 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 23 Apr 2024 05:43:38 +0000 Subject: [PATCH 027/153] Refactor import paths and update auth login functions --- .../common/lib/api/resources/Configuration.ts | 2 +- packages/common/lib/api/resources/Device.ts | 2 +- packages/common/lib/api/resources/Event.ts | 4 ++-- packages/common/lib/api/resources/Feed.ts | 2 +- packages/common/lib/api/resources/Image.ts | 2 +- packages/common/lib/api/resources/Marathon.ts | 2 +- .../common/lib/api/resources/MarathonHour.ts | 2 +- .../common/lib/api/resources/Membership.ts | 2 +- .../common/lib/api/resources/Notification.ts | 4 ++-- packages/common/lib/api/resources/Person.ts | 2 +- .../common/lib/api/resources/PointEntry.ts | 2 +- .../lib/api/resources/PointOpportunity.ts | 2 +- packages/common/lib/api/resources/Team.ts | 2 +- packages/common/lib/api/types/IntervalISO.ts | 18 ++------------- .../src/resolvers/ConfigurationResolver.ts | 19 +++++++-------- .../server/src/resolvers/EventResolver.ts | 23 +++++++++---------- packages/server/src/resolvers/LoginState.ts | 8 +++---- .../server/src/resolvers/PersonResolver.ts | 10 ++++---- .../src/resolvers/PointOpportunityResolver.ts | 15 ++++++------ 19 files changed, 54 insertions(+), 69 deletions(-) diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index c1496c7c..9d35a50f 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -18,7 +18,7 @@ to have additional validation logic in the future. */ @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class ConfigurationNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index c25a55e3..ba027773 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -6,7 +6,7 @@ import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; -@ObjectType({ implements: [TimestampedResource, Node] }) +@ObjectType({ implements: [Node] }) export class DeviceNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index 3ea33e84..cc53b619 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -6,7 +6,7 @@ import { IntervalISO } from "../types/IntervalISO.js"; import { Resource, TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class EventNode extends TimestampedResource implements Node { @Field(() => ID) @@ -32,7 +32,7 @@ export class EventNode extends TimestampedResource implements Node { } @ObjectType({ - implements: [Resource], + implements: [], }) export class EventOccurrenceNode extends Resource { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Feed.ts b/packages/common/lib/api/resources/Feed.ts index d3c2033d..814f16cb 100644 --- a/packages/common/lib/api/resources/Feed.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -15,7 +15,7 @@ import { TimestampedResource } from "./Resource.js"; // }); @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class FeedNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index 9d6b643a..721cdcbe 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -5,7 +5,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class ImageNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index f63751ac..a835e406 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -7,7 +7,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class MarathonNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index e116ac6a..300cc8e9 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -7,7 +7,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class MarathonHourNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index 97e5cab8..5ff30fa1 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -16,7 +16,7 @@ registerEnumType(MembershipPositionType, { }); @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class MembershipNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index c3083605..12743300 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -9,7 +9,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class NotificationNode extends TimestampedResource implements Node { @Field(() => ID) @@ -67,7 +67,7 @@ export const { NotificationConnection, NotificationEdge, NotificationResult } = createNodeClasses(NotificationNode, "Notification"); @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class NotificationDeliveryNode extends TimestampedResource diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index 41e6aaa1..c0efc59a 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -6,7 +6,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class PersonNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index 407b6949..78f9c162 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -4,7 +4,7 @@ import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class PointEntryResource extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index d1c25cda..bdd364ed 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -9,7 +9,7 @@ import { TimestampedResource } from "./Resource.js"; import { TeamType } from "./Team.js"; @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class PointOpportunityResource extends TimestampedResource diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 465067e3..00084528 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -31,7 +31,7 @@ registerEnumType(TeamLegacyStatus, { }); @ObjectType({ - implements: [TimestampedResource, Node], + implements: [Node], }) export class TeamNode extends TimestampedResource implements Node { @Field(() => ID) diff --git a/packages/common/lib/api/types/IntervalISO.ts b/packages/common/lib/api/types/IntervalISO.ts index cd59b098..568aa846 100644 --- a/packages/common/lib/api/types/IntervalISO.ts +++ b/packages/common/lib/api/types/IntervalISO.ts @@ -1,10 +1,11 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { DateTime, Interval } from "luxon"; -import { Field, ObjectType } from "type-graphql"; +import { Field, InputType, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; @ObjectType() +@InputType("IntervalISOInput") export class IntervalISO { @Field(() => DateTimeISOResolver) start!: Date; @@ -22,21 +23,6 @@ export class IntervalISO { return Interval.fromDateTimes(this.startDateTime, this.endDateTime); } - @Field(() => String) - iso8601(): string { - return this.interval.toISO(); - } - - @Field(() => String, { nullable: true }) - duration(): string | null { - return this.interval.toDuration().toISO(); - } - - @Field(() => Boolean) - isEmpty(): boolean { - return this.interval.isEmpty(); - } - static init(start: Date, end: Date): IntervalISO { const self = new IntervalISO(); self.start = start; diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index 70819ded..c87ef15d 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -5,8 +5,9 @@ import { DetailedError, ErrorCode, SortDirection, + dateTimeFromSomething, } from "@ukdanceblue/common"; -import type { DateTime } from "luxon"; +import { DateTimeISOResolver } from "graphql-scalars"; import { Arg, Field, @@ -68,11 +69,11 @@ class CreateConfigurationInput implements Partial { @Field() value!: string; - @Field(() => DateTimeScalar, { nullable: true }) - validAfter!: DateTime | null; + @Field(() => DateTimeISOResolver, { nullable: true }) + validAfter!: Date | null; - @Field(() => DateTimeScalar, { nullable: true }) - validUntil!: DateTime | null; + @Field(() => DateTimeISOResolver, { nullable: true }) + validUntil!: Date | null; } @Resolver(() => ConfigurationNode) @@ -118,8 +119,8 @@ export class ConfigurationResolver { const row = await this.configurationRepository.createConfiguration({ key: input.key, value: input.value, - validAfter: input.validAfter ?? null, - validUntil: input.validUntil ?? null, + validAfter: dateTimeFromSomething(input.validAfter ?? null), + validUntil: dateTimeFromSomething(input.validUntil ?? null), }); auditLogger.dangerous("Configuration created", { configuration: row }); @@ -142,8 +143,8 @@ export class ConfigurationResolver { this.configurationRepository.createConfiguration({ key: i.key, value: i.value, - validAfter: i.validAfter ?? null, - validUntil: i.validUntil ?? null, + validAfter: dateTimeFromSomething(i.validAfter ?? null), + validUntil: dateTimeFromSomething(i.validUntil ?? null), }) ) ); diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index 3035cc5d..9bd02995 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -2,15 +2,14 @@ import type { Prisma } from "@prisma/client"; import { AccessControl, AccessLevel, - DateRangeScalar, DetailedError, ErrorCode, EventNode, FilteredListQueryArgs, ImageNode, + IntervalISO, SortDirection, } from "@ukdanceblue/common"; -import { Interval } from "luxon"; import { Arg, Args, @@ -94,8 +93,8 @@ class ListEventsResponse extends AbstractGraphQLPaginatedResponse { @InputType() export class CreateEventOccurrenceInput { - @Field(() => DateRangeScalar) - interval!: Interval; + @Field(() => IntervalISO) + interval!: IntervalISO; @Field(() => Boolean) fullDay!: boolean; } @@ -126,8 +125,8 @@ export class SetEventOccurrenceInput { "If updating an existing occurrence, the UUID of the occurrence to update", }) uuid!: string | null; - @Field(() => DateRangeScalar) - interval!: Interval; + @Field(() => IntervalISO) + interval!: IntervalISO; @Field(() => Boolean) fullDay!: boolean; } @@ -259,8 +258,8 @@ export class EventResolver { createMany: { data: input.occurrences.map( (occurrence): Prisma.EventOccurrenceCreateManyEventInput => ({ - date: occurrence.interval.start!.toJSDate(), - endDate: occurrence.interval.end!.toJSDate(), + date: occurrence.interval.start, + endDate: occurrence.interval.end, fullDay: occurrence.fullDay, }) ), @@ -312,8 +311,8 @@ export class EventResolver { .filter((occurrence) => occurrence.uuid == null) .map( (occurrence): Prisma.EventOccurrenceCreateManyEventInput => ({ - date: occurrence.interval.start!.toJSDate(), - endDate: occurrence.interval.end!.toJSDate(), + date: occurrence.interval.start, + endDate: occurrence.interval.end, fullDay: occurrence.fullDay, }) ), @@ -326,8 +325,8 @@ export class EventResolver { ): Prisma.EventOccurrenceUpdateManyWithWhereWithoutEventInput => ({ where: { uuid: occurrence.uuid! }, data: { - date: occurrence.interval.start!.toJSDate(), - endDate: occurrence.interval.end!.toJSDate(), + date: occurrence.interval.start, + endDate: occurrence.interval.end, fullDay: occurrence.fullDay, }, }) diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index 9aace5c1..dfae09e7 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -1,4 +1,4 @@ -import { AuthSource, RoleResource } from "@ukdanceblue/common"; +import { AuthSource, DbRole } from "@ukdanceblue/common"; import { Ctx, Field, ObjectType, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; @@ -9,8 +9,8 @@ export class LoginState { @Field(() => Boolean) loggedIn!: boolean; - @Field(() => RoleResource) - role!: RoleResource; + @Field(() => DbRole) + dbRole!: DbRole; @Field(() => AuthSource) authSource!: AuthSource; @@ -23,7 +23,7 @@ export class LoginStateResolver { loginState(@Ctx() ctx: Context.GraphQLContext): LoginState { return { loggedIn: ctx.authenticatedUser != null, - role: RoleResource.fromAuthorization(ctx.userData.auth), + dbRole: ctx.userData.auth.dbRole, authSource: ctx.userData.authSource, }; } diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 9e934417..8c9557e8 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -1,13 +1,13 @@ import { AccessControl, AccessLevel, + DbRole, DetailedError, ErrorCode, FilteredListQueryArgs, MembershipNode, MembershipPositionType, PersonNode, - RoleResource, SortDirection, } from "@ukdanceblue/common"; import { EmailAddressResolver } from "graphql-scalars"; @@ -104,8 +104,8 @@ class CreatePersonInput { @Field(() => String, { nullable: true }) linkblue?: string; - @Field(() => RoleResource, { nullable: true }) - role?: RoleResource; + @Field(() => DbRole, { nullable: true }) + dbRole?: DbRole; @Field(() => [String], { defaultValue: [] }) memberOf?: string[]; @@ -124,8 +124,8 @@ class SetPersonInput { @Field(() => String, { nullable: true }) linkblue?: string; - @Field(() => RoleResource, { nullable: true }) - role?: RoleResource; + @Field(() => DbRole, { nullable: true }) + dbRole?: DbRole; @Field(() => [String], { nullable: true }) memberOf?: string[]; diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index 3645d6e9..e87d3cb3 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -1,5 +1,4 @@ import { - DateTimeScalar, DetailedError, ErrorCode, EventNode, @@ -8,7 +7,7 @@ import { SortDirection, TeamType, } from "@ukdanceblue/common"; -import type { DateTime } from "luxon"; +import { DateTimeISOResolver } from "graphql-scalars"; import { Arg, Args, @@ -66,8 +65,8 @@ class CreatePointOpportunityInput { @Field(() => String) name!: string; - @Field(() => DateTimeScalar, { nullable: true }) - opportunityDate!: DateTime | null; + @Field(() => DateTimeISOResolver, { nullable: true }) + opportunityDate!: Date | null; @Field(() => TeamType) type!: TeamType; @@ -81,8 +80,8 @@ class SetPointOpportunityInput { @Field(() => String, { nullable: true }) name!: string | null; - @Field(() => DateTimeScalar, { nullable: true }) - opportunityDate!: DateTime | null; + @Field(() => DateTimeISOResolver, { nullable: true }) + opportunityDate!: Date | null; @Field(() => TeamType, { nullable: true }) type!: TeamType | null; @@ -172,7 +171,7 @@ export class PointOpportunityResolver { name: input.name, type: input.type, eventParam: input.eventUuid ? { uuid: input.eventUuid } : null, - opportunityDate: input.opportunityDate?.toJSDate() ?? null, + opportunityDate: input.opportunityDate ?? null, }); return CreatePointOpportunityResponse.newOk( @@ -193,7 +192,7 @@ export class PointOpportunityResolver { name: input.name ?? undefined, type: input.type ?? undefined, eventParam: input.eventUuid ? { uuid: input.eventUuid } : undefined, - opportunityDate: input.opportunityDate?.toJSDate() ?? undefined, + opportunityDate: input.opportunityDate ?? undefined, } ); From 1f49e4aa67ffffcba718b4bc5596b8a4bfbd1818 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 17:55:29 +0000 Subject: [PATCH 028/153] Add marathon_id column to teams table and update existing data --- .../20240424003954_team_marathon_relation/migration.sql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql index ce002c7c..2a23d419 100644 --- a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql +++ b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql @@ -10,14 +10,15 @@ -- AlterTable +ALTER TABLE "teams" ADD COLUMN "marathon_id" INTEGER; + WITH Db24Id AS ( SELECT "id" FROM "marathons" WHERE "year" = "DB24" -) ALTER TABLE "teams" ADD COLUMN "marathon_id" INTEGER NOT NULL DEFAULT Db24Id; +) UPDATE "teams" SET "marathon_id" = Db24Id."id" WHERE "marathon_year" = "DB24"; --- Remove the default value for the column `marathon_id` on the table `teams` -ALTER TABLE "teams" ALTER COLUMN "marathon_id" DROP DEFAULT; +ALTER TABLE "teams" ALTER COLUMN "marathon_id" SET NOT NULL; -- DropColumn ALTER TABLE "teams" DROP COLUMN "marathon_year"; From b7ecff49d5a4c58a6638d73a5d862261b9393bdd Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 18:26:05 +0000 Subject: [PATCH 029/153] Add marathon_id column to teams table and update existing data --- .../migration.sql | 34 +++++++++++++++---- packages/server/prisma/schema.prisma | 20 ++++++----- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql index 2a23d419..083d90d8 100644 --- a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql +++ b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql @@ -12,22 +12,42 @@ -- AlterTable ALTER TABLE "teams" ADD COLUMN "marathon_id" INTEGER; -WITH Db24Id AS ( +UPDATE "teams" SET "marathon_id" = ( SELECT "id" FROM "marathons" - WHERE "year" = "DB24" -) UPDATE "teams" SET "marathon_id" = Db24Id."id" WHERE "marathon_year" = "DB24"; + WHERE "year" = 'DB24' +) WHERE "marathon_year" = 'DB24'; ALTER TABLE "teams" ALTER COLUMN "marathon_id" SET NOT NULL; +-- Replace the view +DROP VIEW "teams_with_total_points"; + + -- DropColumn ALTER TABLE "teams" DROP COLUMN "marathon_year"; --- AddForeignKey -ALTER TABLE "teams" ADD CONSTRAINT "teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE CASCADE ON UPDATE CASCADE; +create view teams_with_total_points + (id, uuid, name, type, legacyStatus, persistentIdentifier, marathonId, createdAt, updatedAt, + totalPoints) as +SELECT teams.id, + teams.uuid, + teams.name, + teams.type, + teams.legacy_status AS legacyStatus, + teams.persistent_identifier AS persistentIdentifier, + teams.marathon_id AS marathonId, + teams.created_at AS createdAt, + teams.updated_at AS updatedAt, + COALESCE(points.totalPoints, 0::bigint) AS totalPoints +FROM teams + LEFT JOIN (SELECT sum(entry.points) AS totalPoints, + entry.team_id + FROM point_entries entry + GROUP BY entry.team_id) points ON teams.id = points.team_id; --- DropIndex -DROP INDEX "teams_persistent_identifier_unique"; +-- AddForeignKey +ALTER TABLE "teams" ADD CONSTRAINT "teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE CASCADE ON UPDATE CASCADE, DROP CONSTRAINT "teams_persistent_identifier_unique"; -- CreateIndex CREATE UNIQUE INDEX "teams_marathon_id_persistent_identifier_key" ON "teams"("marathon_id", "persistent_identifier"); \ No newline at end of file diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 0cbbe0e4..3cefed68 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -255,6 +255,7 @@ view TeamsWithTotalPoints { type TeamType legacyStatus TeamLegacyStatus @map("legacystatus") persistentIdentifier String? @unique @map("persistentidentifier") + marathon Marathon @relation(fields: [marathonId], references: [id]) marathonId Int @map("marathonid") createdAt DateTime @map("createdat") @db.Timestamptz(6) updatedAt DateTime @map("updatedat") @db.Timestamptz(6) @@ -318,15 +319,16 @@ model NotificationDelivery { } model Marathon { - id Int @id @default(autoincrement()) - uuid String @unique(map: "marathons_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - year String @unique - startDate DateTime @map("start_date") @db.Timestamptz(6) - endDate DateTime @map("end_date") @db.Timestamptz(6) - hours MarathonHour[] - teams Team[] + id Int @id @default(autoincrement()) + uuid String @unique(map: "marathons_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + year String @unique + startDate DateTime @map("start_date") @db.Timestamptz(6) + endDate DateTime @map("end_date") @db.Timestamptz(6) + hours MarathonHour[] + teams Team[] + teamsWithTotalPoints TeamsWithTotalPoints[] @@index([uuid], map: "marathons_uuid") @@map("marathons") From 7dbce3151f60a15f43e82a061ee66131009278a1 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 18:34:35 +0000 Subject: [PATCH 030/153] Update resource model properties to use 'id' instead of 'uuid' --- packages/common/lib/api/resources/Membership.ts | 7 ++++++- packages/common/lib/api/resources/PointEntry.ts | 8 ++++---- packages/common/lib/api/resources/PointOpportunity.ts | 9 +++------ .../configuration/configurationModelToResource.ts | 2 +- .../repositories/device/deviceModelToResource.test.ts | 4 ++-- .../src/repositories/device/deviceModelToResource.ts | 2 +- .../src/repositories/event/eventModelToResource.ts | 2 +- .../src/repositories/image/imageModelToResource.ts | 2 +- .../repositories/marathon/marathonModelToResource.ts | 10 ++++------ .../marathonHour/marathonHourModelToResource.test.ts | 8 ++++---- .../marathonHour/marathonHourModelToResource.ts | 8 ++++---- .../membership/membershipModelToResource.ts | 5 +++-- .../notification/notificationModelToResource.ts | 2 +- .../notificationDeliveryModelToResource.ts | 2 +- .../pointEntry/pointEntryModelToResource.ts | 2 +- .../pointOpportunityModelToResource.ts | 2 +- .../src/repositories/team/teamModelToResource.ts | 8 +------- .../src/repositories/team/teamRepositoryUtils.ts | 7 ++++++- 18 files changed, 45 insertions(+), 45 deletions(-) diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index 5ff30fa1..c437d9c6 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -29,7 +29,12 @@ export class MembershipNode extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { + public static init(init: { + id: string; + position: MembershipPositionType; + createdAt?: Date | null; + updatedAt?: Date | null; + }) { return MembershipNode.doInit(init); } } diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index 78f9c162..37ca8d0f 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -6,7 +6,7 @@ import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) -export class PointEntryResource extends TimestampedResource implements Node { +export class PointEntryNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String, { nullable: true }) @@ -18,10 +18,10 @@ export class PointEntryResource extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return PointEntryResource.doInit(init); + public static init(init: Partial) { + return PointEntryNode.doInit(init); } } export const { PointEntryConnection, PointEntryEdge, PointEntryResult } = - createNodeClasses(PointEntryResource, "PointEntry"); + createNodeClasses(PointEntryNode, "PointEntry"); diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index bdd364ed..192857af 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -11,10 +11,7 @@ import { TeamType } from "./Team.js"; @ObjectType({ implements: [Node], }) -export class PointOpportunityResource - extends TimestampedResource - implements Node -{ +export class PointOpportunityNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; @Field(() => String) @@ -31,7 +28,7 @@ export class PointOpportunityResource return this.id; } - public static init(init: Partial) { - return PointOpportunityResource.doInit(init); + public static init(init: Partial) { + return PointOpportunityNode.doInit(init); } } diff --git a/packages/server/src/repositories/configuration/configurationModelToResource.ts b/packages/server/src/repositories/configuration/configurationModelToResource.ts index 130b7b99..aa55f18a 100644 --- a/packages/server/src/repositories/configuration/configurationModelToResource.ts +++ b/packages/server/src/repositories/configuration/configurationModelToResource.ts @@ -5,7 +5,7 @@ export function configurationModelToResource( configuration: Configuration ): ConfigurationNode { return ConfigurationNode.init({ - uuid: configuration.uuid, + id: configuration.uuid, key: configuration.key, value: configuration.value, validAfter: configuration.validAfter, diff --git a/packages/server/src/repositories/device/deviceModelToResource.test.ts b/packages/server/src/repositories/device/deviceModelToResource.test.ts index 4092eacc..0a8b3d95 100644 --- a/packages/server/src/repositories/device/deviceModelToResource.test.ts +++ b/packages/server/src/repositories/device/deviceModelToResource.test.ts @@ -22,7 +22,7 @@ describe("deviceModelToResource", () => { expect(resource).toBeInstanceOf(DeviceNode); expect(resource).toStrictEqual( DeviceNode.init({ - uuid: "uuid", + id: "uuid", lastLogin: new Date("2021-01-01T00:00:00Z"), createdAt: new Date("2021-01-01T00:00:00Z"), updatedAt: new Date("2021-01-01T00:00:00Z"), @@ -46,7 +46,7 @@ describe("deviceModelToResource", () => { expect(resource).toStrictEqual( DeviceNode.init({ - uuid: "uuid", + id: "uuid", lastLogin: null, createdAt: new Date("2021-01-01T00:00:00Z"), updatedAt: new Date("2021-01-01T00:00:00Z"), diff --git a/packages/server/src/repositories/device/deviceModelToResource.ts b/packages/server/src/repositories/device/deviceModelToResource.ts index 9b53da9b..d6fc0c6c 100644 --- a/packages/server/src/repositories/device/deviceModelToResource.ts +++ b/packages/server/src/repositories/device/deviceModelToResource.ts @@ -3,7 +3,7 @@ import { DeviceNode } from "@ukdanceblue/common"; export function deviceModelToResource(deviceModel: Device): DeviceNode { return DeviceNode.init({ - uuid: deviceModel.uuid, + id: deviceModel.uuid, lastLogin: deviceModel.lastSeen, createdAt: deviceModel.createdAt, updatedAt: deviceModel.updatedAt, diff --git a/packages/server/src/repositories/event/eventModelToResource.ts b/packages/server/src/repositories/event/eventModelToResource.ts index f5e903a6..f5510c1b 100644 --- a/packages/server/src/repositories/event/eventModelToResource.ts +++ b/packages/server/src/repositories/event/eventModelToResource.ts @@ -10,7 +10,7 @@ export function eventModelToResource( occurrences: EventOccurrenceNode[] = [] ): EventNode { return EventNode.init({ - uuid: eventModel.uuid, + id: eventModel.uuid, title: eventModel.title, summary: eventModel.summary, description: eventModel.description, diff --git a/packages/server/src/repositories/image/imageModelToResource.ts b/packages/server/src/repositories/image/imageModelToResource.ts index 57ab640b..9d02b706 100644 --- a/packages/server/src/repositories/image/imageModelToResource.ts +++ b/packages/server/src/repositories/image/imageModelToResource.ts @@ -31,7 +31,7 @@ export async function imageModelToResource( } return ImageNode.init({ - uuid: imageModel.uuid, + id: imageModel.uuid, url: fileData?.url ?? null, mimeType: fileData?.mimeType ?? "application/octet-stream", // "application/octet-stream" is the default MIME type if the file is not found thumbHash: imageModel.thumbHash?.toString("base64"), diff --git a/packages/server/src/repositories/marathon/marathonModelToResource.ts b/packages/server/src/repositories/marathon/marathonModelToResource.ts index 88ce43d0..424675b5 100644 --- a/packages/server/src/repositories/marathon/marathonModelToResource.ts +++ b/packages/server/src/repositories/marathon/marathonModelToResource.ts @@ -1,11 +1,9 @@ import type { Marathon } from "@prisma/client"; -import { MarathonResource } from "@ukdanceblue/common"; +import { MarathonNode } from "@ukdanceblue/common"; -export function marathonModelToResource( - marathonModel: Marathon -): MarathonResource { - return MarathonResource.init({ - uuid: marathonModel.uuid, +export function marathonModelToResource(marathonModel: Marathon): MarathonNode { + return MarathonNode.init({ + id: marathonModel.uuid, year: marathonModel.year, startDate: marathonModel.startDate, endDate: marathonModel.endDate, diff --git a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.test.ts b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.test.ts index a3a59b7b..1a790cc2 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.test.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.test.ts @@ -1,11 +1,11 @@ import type { MarathonHour } from "@prisma/client"; -import { MarathonHourResource } from "@ukdanceblue/common"; +import { MarathonHourNode } from "@ukdanceblue/common"; import { describe, expect, it } from "vitest"; import { marathonHourModelToResource } from "./marathonHourModelToResource.js"; describe("marathonHourModelToResource", () => { - it("should correctly transform MarathonHour to MarathonHourResource", () => { + it("should correctly transform MarathonHour to MarathonHourNode", () => { const now = new Date(); const marathonHourModel: MarathonHour = { id: 0, @@ -23,8 +23,8 @@ describe("marathonHourModelToResource", () => { const nowString = now.toISOString(); - expect(result).toBeInstanceOf(MarathonHourResource); - expect(result.uuid).toBe("test-uuid"); + expect(result).toBeInstanceOf(MarathonHourNode); + expect(result.id).toBe("test-uuid"); expect(result.title).toBe("test-title"); expect(result.details).toBe("test-details"); expect(result.durationInfo).toBe("test-durationInfo"); diff --git a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts index a6d14a80..880df403 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourModelToResource.ts @@ -1,11 +1,11 @@ import type { MarathonHour } from "@prisma/client"; -import { MarathonHourResource } from "@ukdanceblue/common"; +import { MarathonHourNode } from "@ukdanceblue/common"; export function marathonHourModelToResource( marathonHourModel: MarathonHour -): MarathonHourResource { - return MarathonHourResource.init({ - uuid: marathonHourModel.uuid, +): MarathonHourNode { + return MarathonHourNode.init({ + id: marathonHourModel.uuid, title: marathonHourModel.title, details: marathonHourModel.details, durationInfo: marathonHourModel.durationInfo, diff --git a/packages/server/src/repositories/membership/membershipModelToResource.ts b/packages/server/src/repositories/membership/membershipModelToResource.ts index c1423a9a..4565d5f1 100644 --- a/packages/server/src/repositories/membership/membershipModelToResource.ts +++ b/packages/server/src/repositories/membership/membershipModelToResource.ts @@ -1,10 +1,11 @@ +import type { Membership } from "@prisma/client"; import { MembershipNode } from "@ukdanceblue/common"; export function membershipModelToResource( - membershipModel: MembershipNode + membershipModel: Membership ): MembershipNode { return MembershipNode.init({ - uuid: membershipModel.uuid, + id: membershipModel.uuid, position: membershipModel.position, createdAt: membershipModel.createdAt, updatedAt: membershipModel.updatedAt, diff --git a/packages/server/src/repositories/notification/notificationModelToResource.ts b/packages/server/src/repositories/notification/notificationModelToResource.ts index 5e693f4d..a426400d 100644 --- a/packages/server/src/repositories/notification/notificationModelToResource.ts +++ b/packages/server/src/repositories/notification/notificationModelToResource.ts @@ -5,7 +5,7 @@ export function notificationModelToResource( notificationModel: Notification ): NotificationNode { return NotificationNode.init({ - uuid: notificationModel.uuid, + id: notificationModel.uuid, title: notificationModel.title, body: notificationModel.body, url: notificationModel.url ? new URL(notificationModel.url) : null, diff --git a/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts b/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts index 3fa0cfe5..882ea7fc 100644 --- a/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts +++ b/packages/server/src/repositories/notificationDelivery/notificationDeliveryModelToResource.ts @@ -5,7 +5,7 @@ export function notificationDeliveryModelToResource( notificationDeliveryModel: NotificationDelivery ): NotificationDeliveryNode { return NotificationDeliveryNode.init({ - uuid: notificationDeliveryModel.uuid, + id: notificationDeliveryModel.uuid, sentAt: notificationDeliveryModel.sentAt, receiptCheckedAt: notificationDeliveryModel.receiptCheckedAt, chunkUuid: notificationDeliveryModel.chunkUuid, diff --git a/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts b/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts index f953b10d..0405b96a 100644 --- a/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts +++ b/packages/server/src/repositories/pointEntry/pointEntryModelToResource.ts @@ -5,7 +5,7 @@ export function pointEntryModelToResource( pointEntryModel: PointEntry ): PointEntryNode { return PointEntryNode.init({ - uuid: pointEntryModel.uuid, + id: pointEntryModel.uuid, points: pointEntryModel.points, comment: pointEntryModel.comment, createdAt: pointEntryModel.createdAt, diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts index d0ac731d..d6d66bbd 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityModelToResource.ts @@ -5,7 +5,7 @@ export function pointOpportunityModelToResource( pointOpportunityModel: PointOpportunity ): PointOpportunityNode { return PointOpportunityNode.init({ - uuid: pointOpportunityModel.uuid, + id: pointOpportunityModel.uuid, name: pointOpportunityModel.name, type: pointOpportunityModel.type, opportunityDate: pointOpportunityModel.opportunityDate, diff --git a/packages/server/src/repositories/team/teamModelToResource.ts b/packages/server/src/repositories/team/teamModelToResource.ts index 8104dbf9..3209fcc4 100644 --- a/packages/server/src/repositories/team/teamModelToResource.ts +++ b/packages/server/src/repositories/team/teamModelToResource.ts @@ -1,15 +1,9 @@ import type { Team } from "@prisma/client"; import { TeamNode } from "@ukdanceblue/common"; -const marathonYearRegex = /^DB\d{2}$/; - export function teamModelToResource(teamModel: Team): TeamNode { - if (!marathonYearRegex.test(teamModel.marathonYear)) { - throw new Error(`Invalid marathon year: ${teamModel.marathonYear}`); - } - return TeamNode.init({ - uuid: teamModel.uuid, + id: teamModel.uuid, name: teamModel.name, type: teamModel.type, legacyStatus: teamModel.legacyStatus, diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index cfc5e03a..604fcd9b 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -49,8 +49,13 @@ export function buildTeamWhere( where[filter.field] = dateFilterToPrisma(filter); break; } + case "marathonYear": { + where["marathon"] = { + year: oneOfFilterToPrisma(filter), + }; + break; + } case "type": - case "marathonYear": case "legacyStatus": { where[filter.field] = oneOfFilterToPrisma(filter); break; From 1731924e9dc00483e57d951466161912893b7847 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 18:39:08 +0000 Subject: [PATCH 031/153] Update resource model properties to use 'id' instead of 'uuid' --- .../server/src/resolvers/DeviceResolver.ts | 6 ++-- .../server/src/resolvers/EventResolver.ts | 2 +- packages/server/src/resolvers/FeedResolver.ts | 2 +- .../src/resolvers/MarathonHourResolver.ts | 26 +++++++-------- .../server/src/resolvers/MarathonResolver.ts | 32 +++++++++---------- .../src/resolvers/MembershipResolver.ts | 4 +-- .../src/resolvers/NotificationResolver.ts | 6 ++-- .../server/src/resolvers/PersonResolver.ts | 4 +-- .../src/resolvers/PointEntryResolver.ts | 6 ++-- .../src/resolvers/PointOpportunityResolver.ts | 2 +- packages/server/src/resolvers/TeamResolver.ts | 8 ++--- 11 files changed, 49 insertions(+), 49 deletions(-) diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 7788f201..4bc0041d 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -188,7 +188,7 @@ export class DeviceResolver { async lastLoggedInUser( @Root() device: DeviceNode ): Promise { - const user = await this.deviceRepository.getLastLoggedInUser(device.uuid); + const user = await this.deviceRepository.getLastLoggedInUser(device.id); return user == null ? null : personModelToResource(user); } @@ -198,7 +198,7 @@ export class DeviceResolver { @Root() device: DeviceNode, @Args(() => NotificationDeliveriesArgs) query: NotificationDeliveriesArgs ): Promise { - const row = await this.deviceRepository.getDeviceByUuid(device.uuid); + const row = await this.deviceRepository.getDeviceByUuid(device.id); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Device not found"); @@ -216,7 +216,7 @@ export class DeviceResolver { const rows = await this.deviceRepository.findNotificationDeliveriesForDevice( - device.uuid, + device.id, { skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index 9bd02995..80745cfa 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -396,7 +396,7 @@ export class EventResolver { @FieldResolver(() => [ImageNode]) async images(@Root() event: EventNode): Promise { const rows = await this.eventImageRepository.findEventImagesByEventUnique({ - uuid: event.uuid, + uuid: event.id, }); return Promise.all( diff --git a/packages/server/src/resolvers/FeedResolver.ts b/packages/server/src/resolvers/FeedResolver.ts index d8ed74fd..a0d78cd7 100644 --- a/packages/server/src/resolvers/FeedResolver.ts +++ b/packages/server/src/resolvers/FeedResolver.ts @@ -130,7 +130,7 @@ export class FeedResolver { } @FieldResolver(() => ImageNode, { nullable: true }) - async image(@Root() { uuid }: FeedNode) { + async image(@Root() { id: uuid }: FeedNode) { const row = await this.feedRepository.getFeedItemImage({ uuid }); if (row == null) { return null; diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index 0cbd2e63..0fc8eed7 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -3,7 +3,7 @@ import { ErrorCode, FilteredListQueryArgs, ImageNode, - MarathonHourResource, + MarathonHourNode, } from "@ukdanceblue/common"; import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; import { @@ -27,11 +27,11 @@ import { marathonHourModelToResource } from "../repositories/marathonHour/marath import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ObjectType("ListMarathonHoursResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListMarathonHoursResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [MarathonHourResource]) - data!: MarathonHourResource[]; +class ListMarathonHoursResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [MarathonHourNode]) + data!: MarathonHourNode[]; } @InputType() @@ -93,14 +93,14 @@ class ListMarathonHoursArgs extends FilteredListQueryArgs< date: ["shownStartingAt", "createdAt", "updatedAt"], }) {} -@Resolver(() => MarathonHourResource) +@Resolver(() => MarathonHourNode) @Service() export class MarathonHourResolver { constructor( private readonly marathonHourRepository: MarathonHourRepository ) {} - @Query(() => MarathonHourResource) + @Query(() => MarathonHourNode) async marathonHour(@Arg("uuid") uuid: string) { const marathonHour = await this.marathonHourRepository.findMarathonHourByUnique({ @@ -112,7 +112,7 @@ export class MarathonHourResolver { return marathonHourModelToResource(marathonHour); } - @Query(() => MarathonHourResource, { nullable: true }) + @Query(() => MarathonHourNode, { nullable: true }) async currentMarathonHour() { const marathonHour = await this.marathonHourRepository.findCurrentMarathonHour(); @@ -136,11 +136,11 @@ export class MarathonHourResolver { } @FieldResolver(() => [ImageNode]) - async mapImages(@Root() marathonHour: MarathonHourResource) { - return this.marathonHourRepository.getMaps({ uuid: marathonHour.uuid }); + async mapImages(@Root() marathonHour: MarathonHourNode) { + return this.marathonHourRepository.getMaps({ uuid: marathonHour.id }); } - @Mutation(() => MarathonHourResource) + @Mutation(() => MarathonHourNode) async createMarathonHour( @Arg("input") input: CreateMarathonHourInput, @Arg("marathonUuid") marathonUuid: string @@ -152,7 +152,7 @@ export class MarathonHourResolver { return marathonHourModelToResource(marathonHour); } - @Mutation(() => MarathonHourResource) + @Mutation(() => MarathonHourNode) async setMarathonHour( @Arg("uuid") uuid: string, @Arg("input") input: SetMarathonHourInput @@ -177,7 +177,7 @@ export class MarathonHourResolver { } } - @Mutation(() => MarathonHourResource) + @Mutation(() => MarathonHourNode) async addMap(@Arg("uuid") uuid: string, @Arg("imageUuid") imageUuid: string) { const marathonHour = await this.marathonHourRepository.addMap( { uuid }, diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index aed0d0be..9ffad575 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -2,8 +2,8 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, - MarathonHourResource, - MarathonResource, + MarathonHourNode, + MarathonNode, SortDirection, } from "@ukdanceblue/common"; import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; @@ -29,11 +29,11 @@ import { marathonHourModelToResource } from "../repositories/marathonHour/marath import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ObjectType("ListMarathonsResponse", { - implements: AbstractGraphQLPaginatedResponse, + implements: AbstractGraphQLPaginatedResponse, }) -class ListMarathonsResponse extends AbstractGraphQLPaginatedResponse { - @Field(() => [MarathonResource]) - data!: MarathonResource[]; +class ListMarathonsResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [MarathonNode]) + data!: MarathonNode[]; } @InputType() @@ -74,12 +74,12 @@ class ListMarathonsArgs extends FilteredListQueryArgs< date: ["startDate", "endDate", "createdAt", "updatedAt"], }) {} -@Resolver(() => MarathonResource) +@Resolver(() => MarathonNode) @Service() export class MarathonResolver { constructor(private readonly marathonRepository: MarathonRepository) {} - @Query(() => MarathonResource) + @Query(() => MarathonNode) async marathon(@Arg("uuid") uuid: string) { const marathon = await this.marathonRepository.findMarathonByUnique({ uuid, @@ -90,7 +90,7 @@ export class MarathonResolver { return marathonModelToResource(marathon); } - @Query(() => MarathonResource) + @Query(() => MarathonNode) async marathonForYear(@Arg("year") year: string) { const marathon = await this.marathonRepository.findMarathonByUnique({ year, @@ -127,7 +127,7 @@ export class MarathonResolver { }); } - @Query(() => MarathonResource, { nullable: true }) + @Query(() => MarathonNode, { nullable: true }) async currentMarathon() { const marathon = await this.marathonRepository.findCurrentMarathon(); if (marathon == null) { @@ -136,7 +136,7 @@ export class MarathonResolver { return marathonModelToResource(marathon); } - @Query(() => MarathonResource, { nullable: true }) + @Query(() => MarathonNode, { nullable: true }) async nextMarathon() { const marathon = await this.marathonRepository.findNextMarathon(); if (marathon == null) { @@ -145,13 +145,13 @@ export class MarathonResolver { return marathonModelToResource(marathon); } - @Mutation(() => MarathonResource) + @Mutation(() => MarathonNode) async createMarathon(@Arg("input") input: CreateMarathonInput) { const marathon = await this.marathonRepository.createMarathon(input); return marathonModelToResource(marathon); } - @Mutation(() => MarathonResource) + @Mutation(() => MarathonNode) async setMarathon( @Arg("uuid") uuid: string, @Arg("input") input: SetMarathonInput @@ -174,10 +174,10 @@ export class MarathonResolver { } } - @FieldResolver(() => [MarathonHourResource]) - async hours(@Root() marathon: MarathonResource) { + @FieldResolver(() => [MarathonHourNode]) + async hours(@Root() marathon: MarathonNode) { const rows = await this.marathonRepository.getMarathonHours({ - uuid: marathon.uuid, + uuid: marathon.id, }); return rows.map(marathonHourModelToResource); } diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 38f5d060..94098aa7 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -20,7 +20,7 @@ export class MembershipResolver { @FieldResolver(() => PersonNode) async person(@Root() membership: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( - { uuid: membership.uuid }, + { uuid: membership.id }, { person: true, } @@ -36,7 +36,7 @@ export class MembershipResolver { @FieldResolver(() => TeamNode) async team(@Root() membership: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( - { uuid: membership.uuid }, + { uuid: membership.id }, { team: true, } diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 47d00d58..5c3be01d 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -532,7 +532,7 @@ export class NotificationResolver { accessLevel: AccessLevel.CommitteeChairOrCoordinator, }) @FieldResolver(() => Int, { name: "deliveryCount" }) - async deliveryCount(@Root() { uuid }: NotificationNode): Promise { + async deliveryCount(@Root() { id: uuid }: NotificationNode): Promise { return this.notificationRepository.countDeliveriesForNotification({ uuid }); } @@ -543,7 +543,7 @@ export class NotificationResolver { name: "deliveryIssueCount", }) async deliveryIssueCount( - @Root() { uuid }: NotificationNode + @Root() { id: uuid }: NotificationNode ): Promise { const issues = await this.notificationRepository.countFailedDeliveriesForNotification({ @@ -568,7 +568,7 @@ export class NotificationDeliveryResolver { name: "notification", }) async getNotificationForDelivery( - @Root() { uuid }: NotificationDeliveryNode + @Root() { id: uuid }: NotificationDeliveryNode ): Promise { const notification = await this.notificationDeliveryRepository.findNotificationForDelivery({ diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 8c9557e8..0f2cbac5 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -303,7 +303,7 @@ export class PersonResolver { @FieldResolver(() => [MembershipNode]) async teams(@Root() person: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson({ - uuid: person.uuid, + uuid: person.id, }); if (models == null) { @@ -319,7 +319,7 @@ export class PersonResolver { }) async captaincies(@Root() person: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson( - { uuid: person.uuid }, + { uuid: person.id }, { position: MembershipPositionType.Captain } ); diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 4599d581..6ca71b42 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -175,7 +175,7 @@ export class PointEntryResolver { @Root() pointEntry: PointEntryNode ): Promise { const model = await this.pointEntryRepository.getPointEntryPersonFrom({ - uuid: pointEntry.uuid, + uuid: pointEntry.id, }); return model ? personModelToResource(model) : null; @@ -184,7 +184,7 @@ export class PointEntryResolver { @FieldResolver(() => TeamNode) async team(@Root() pointEntry: PointEntryNode): Promise { const model = await this.pointEntryRepository.getPointEntryTeam({ - uuid: pointEntry.uuid, + uuid: pointEntry.id, }); if (model == null) { @@ -199,7 +199,7 @@ export class PointEntryResolver { @Root() pointEntry: PointEntryNode ): Promise { const model = await this.pointEntryRepository.getPointEntryOpportunity({ - uuid: pointEntry.uuid, + uuid: pointEntry.id, }); return model ? pointOpportunityModelToResource(model) : null; diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index e87d3cb3..d3a325e0 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -228,7 +228,7 @@ export class PointOpportunityResolver { ): Promise { const model = await this.pointOpportunityRepository.getEventForPointOpportunity({ - uuid: pointOpportunity.uuid, + uuid: pointOpportunity.id, }); return model ? eventModelToResource(model) : null; diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 1f142c80..66692988 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -313,7 +313,7 @@ export class TeamResolver { @FieldResolver(() => [MembershipNode]) async members(@Root() team: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam({ - uuid: team.uuid, + uuid: team.id, }); return memberships.map((row) => membershipModelToResource(row)); @@ -325,7 +325,7 @@ export class TeamResolver { }) async captains(@Root() team: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam( - { uuid: team.uuid }, + { uuid: team.id }, { captainsOnly: true } ); @@ -346,7 +346,7 @@ export class TeamResolver { @FieldResolver(() => [PointEntryNode]) async pointEntries(@Root() team: TeamNode): Promise { const rows = await this.teamRepository.getTeamPointEntries({ - uuid: team.uuid, + uuid: team.id, }); return rows.map((row) => pointEntryModelToResource(row)); @@ -356,7 +356,7 @@ export class TeamResolver { @FieldResolver(() => Int) async totalPoints(@Root() team: TeamNode): Promise { const result = await this.teamRepository.getTotalTeamPoints({ - uuid: team.uuid, + uuid: team.id, }); return result._sum.points ?? 0; From f4646ac77b869b92606f0faa512371a7cf3b3654 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 19:21:18 +0000 Subject: [PATCH 032/153] Update resource model properties to use 'id' instead of 'uuid' --- .../repositories/person/PersonRepository.ts | 53 +++++++++++++------ packages/server/src/repositories/shared.ts | 1 + .../src/repositories/team/TeamRepository.ts | 49 ++++++++++++----- packages/server/src/resolvers/TeamResolver.ts | 2 +- packages/server/src/resolvers/context.ts | 2 +- 5 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 packages/server/src/repositories/shared.ts diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 855d5354..3483ac44 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -5,6 +5,8 @@ import { CommitteeIdentifier, CommitteeRole, DbRole, + DetailedError, + ErrorCode, MembershipPositionType, SortDirection, TeamLegacyStatus, @@ -414,6 +416,39 @@ export class PersonRepository { } async getDemoUser() { + let demoTeam = await this.prisma.team.findFirst({ + where: { + legacyStatus: TeamLegacyStatus.DemoTeam, + }, + }); + + if (!demoTeam) { + const someMarathon = await this.prisma.marathon.findFirst({ + orderBy: { + year: "asc", + }, + }); + + if (!someMarathon) { + throw new DetailedError( + ErrorCode.NotFound, + "No marathons found for demo user" + ); + } + + demoTeam = await this.prisma.team.create({ + data: { + name: "Demo Team", + type: "Spirit", + marathon: { + connect: someMarathon, + }, + legacyStatus: TeamLegacyStatus.DemoTeam, + persistentIdentifier: "demo-team", + }, + }); + } + return this.prisma.person.upsert({ where: { authIdPairs: { @@ -431,19 +466,7 @@ export class PersonRepository { memberships: { create: { team: { - connectOrCreate: { - where: { - persistentIdentifier: "demo-team", - legacyStatus: TeamLegacyStatus.DemoTeam, - }, - create: { - name: "Demo Team", - type: "Spirit", - marathonYear: "DB24", - legacyStatus: TeamLegacyStatus.DemoTeam, - persistentIdentifier: "demo-team", - }, - }, + connect: demoTeam, }, position: MembershipPositionType.Captain, }, @@ -451,9 +474,7 @@ export class PersonRepository { pointEntries: { create: { team: { - connect: { - persistentIdentifier: "demo-team", - }, + connect: demoTeam, }, points: 1, comment: "Demo point", diff --git a/packages/server/src/repositories/shared.ts b/packages/server/src/repositories/shared.ts new file mode 100644 index 00000000..f2e9ee83 --- /dev/null +++ b/packages/server/src/repositories/shared.ts @@ -0,0 +1 @@ +export type SimpleUniqueParam = { id: number } | { uuid: string }; diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index bb8fa861..da65ec73 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -8,6 +8,7 @@ import { TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { SimpleUniqueParam } from "../shared.js"; import { buildTeamOrder, buildTeamWhere } from "./teamRepositoryUtils.js"; @@ -47,13 +48,37 @@ export type TeamOrderKeys = | "name" | "totalPoints"; -type UniqueTeamParam = { id: number } | { uuid: string }; +type MarathonParam = SimpleUniqueParam | { year: MarathonYearString }; + +function makeMarathonWhere(param: MarathonParam[]) { + const marathonIds: number[] = []; + const marathonUuids: string[] = []; + const marathonYears: MarathonYearString[] = []; + for (const m of param) { + if ("id" in m) { + marathonIds.push(m.id); + } else if ("uuid" in m) { + marathonUuids.push(m.uuid); + } else if ("year" in m) { + marathonYears.push(m.year); + } else { + m satisfies never; + } + } + return { + OR: [ + { id: { in: marathonIds } }, + { uuid: { in: marathonUuids } }, + { year: { in: marathonYears } }, + ], + }; +} @Service() export class TeamRepository { constructor(private prisma: PrismaClient) {} - findTeamByUnique(param: UniqueTeamParam) { + findTeamByUnique(param: SimpleUniqueParam) { return this.prisma.team.findUnique({ where: param }); } @@ -64,7 +89,7 @@ export class TeamRepository { take, onlyDemo, legacyStatus, - marathonYear, + marathon, type, }: { filters?: readonly TeamFilters[] | undefined | null; @@ -76,7 +101,7 @@ export class TeamRepository { take?: number | undefined | null; onlyDemo?: boolean; legacyStatus?: TeamLegacyStatus[] | undefined | null; - marathonYear?: MarathonYearString[] | undefined | null; + marathon: MarathonParam[] | undefined | null; type?: TeamType[] | undefined | null; }) { const where = buildTeamWhere(filters); @@ -85,7 +110,7 @@ export class TeamRepository { return this.prisma.teamsWithTotalPoints.findMany({ where: { type: type ? { in: type } : undefined, - marathonYear: marathonYear ? { in: marathonYear } : undefined, + marathon: makeMarathonWhere(marathon ?? []), ...where, legacyStatus: legacyStatus @@ -109,13 +134,13 @@ export class TeamRepository { filters, onlyDemo, legacyStatus, - marathonYear, + marathon, type, }: { filters?: readonly TeamFilters[] | undefined | null; onlyDemo?: boolean; legacyStatus?: TeamLegacyStatus[] | undefined | null; - marathonYear?: MarathonYearString[] | undefined | null; + marathon: MarathonParam[] | undefined | null; type?: TeamType[] | undefined | null; }) { const where = buildTeamWhere(filters); @@ -123,7 +148,7 @@ export class TeamRepository { return this.prisma.teamsWithTotalPoints.count({ where: { type: type ? { in: type } : undefined, - marathonYear: marathonYear ? { in: marathonYear } : undefined, + marathon: makeMarathonWhere(marathon ?? []), ...where, legacyStatus: legacyStatus @@ -160,7 +185,7 @@ export class TeamRepository { }); } - getTotalTeamPoints(param: UniqueTeamParam) { + getTotalTeamPoints(param: SimpleUniqueParam) { return this.prisma.pointEntry.aggregate({ _sum: { points: true, @@ -171,7 +196,7 @@ export class TeamRepository { }); } - getTeamPointEntries(param: UniqueTeamParam) { + getTeamPointEntries(param: SimpleUniqueParam) { return this.prisma.pointEntry.findMany({ where: { team: param, @@ -183,7 +208,7 @@ export class TeamRepository { return this.prisma.team.create({ data }); } - updateTeam(param: UniqueTeamParam, data: Prisma.TeamUpdateInput) { + updateTeam(param: SimpleUniqueParam, data: Prisma.TeamUpdateInput) { try { return this.prisma.team.update({ where: param, data }); } catch (error) { @@ -198,7 +223,7 @@ export class TeamRepository { } } - deleteTeam(param: UniqueTeamParam) { + deleteTeam(param: SimpleUniqueParam) { try { return this.prisma.team.delete({ where: param }); } catch (error) { diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 66692988..b6abf2ba 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -175,7 +175,7 @@ export class TeamResolver { take: query.pageSize, onlyDemo: ctx.userData.authSource === AuthSource.Demo, legacyStatus: query.legacyStatus, - marathonYear: query.marathonYear, + marathon: query.marathonYear, type: query.type, }), this.teamRepository.countTeams({ diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 20f2d891..a02b5c49 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -60,7 +60,7 @@ export const graphqlContextFunction: ContextFunction< return { authenticatedUser: personResource, userData: { - auth: personResource.role.toAuthorization(), + auth, userId, teamIds: person.memberships.map((m) => m.team.uuid), captainOfTeamIds: person.memberships From c2655ad6063e15a5e91789b35373cd2d5ddd5e2c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 27 Apr 2024 19:38:44 +0000 Subject: [PATCH 033/153] Add foreign key constraint for marathon_id in teams table --- .../migration.sql | 2 +- .../migration.sql | 38 ++++++++++++++++ packages/server/prisma/schema.prisma | 44 ++++++++++++++----- 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 packages/server/prisma/migrations/20240427193820_team_committees/migration.sql diff --git a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql index 083d90d8..306bd006 100644 --- a/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql +++ b/packages/server/prisma/migrations/20240424003954_team_marathon_relation/migration.sql @@ -47,7 +47,7 @@ FROM teams GROUP BY entry.team_id) points ON teams.id = points.team_id; -- AddForeignKey -ALTER TABLE "teams" ADD CONSTRAINT "teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE CASCADE ON UPDATE CASCADE, DROP CONSTRAINT "teams_persistent_identifier_unique"; +ALTER TABLE "teams" ADD CONSTRAINT "teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- CreateIndex CREATE UNIQUE INDEX "teams_marathon_id_persistent_identifier_key" ON "teams"("marathon_id", "persistent_identifier"); \ No newline at end of file diff --git a/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql b/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql new file mode 100644 index 00000000..f4fe60d4 --- /dev/null +++ b/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql @@ -0,0 +1,38 @@ +/* + Warnings: + + - A unique constraint covering the columns `[marathon_id,committee_id]` on the table `teams` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropIndex +DROP INDEX "teams_persistent_identifier_unique"; + +-- AlterTable +ALTER TABLE "teams" ADD COLUMN "committee_id" INTEGER; + +-- CreateTable +CREATE TABLE "committees" ( + "id" SERIAL NOT NULL, + "uuid" UUID NOT NULL, + "identifier" "enum_people_committee_name" NOT NULL, + "parent_committee_id" INTEGER, + "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) NOT NULL, + + CONSTRAINT "committees_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "committees_uuid_unique" ON "committees"("uuid"); + +-- CreateIndex +CREATE INDEX "committees_uuid" ON "committees"("uuid"); + +-- CreateIndex +CREATE UNIQUE INDEX "teams_marathon_id_committee_id_key" ON "teams"("marathon_id", "committee_id"); + +-- AddForeignKey +ALTER TABLE "teams" ADD CONSTRAINT "teams_committee_id_fkey" FOREIGN KEY ("committee_id") REFERENCES "committees"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "committees" ADD CONSTRAINT "committees_parent_committee_id_fkey" FOREIGN KEY ("parent_committee_id") REFERENCES "committees"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 3cefed68..216b3eb3 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -230,24 +230,44 @@ model PointOpportunity { } model Team { - id Int @id @default(autoincrement()) - uuid String @unique(map: "teams_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - name String - type TeamType - legacyStatus TeamLegacyStatus @map("legacy_status") - marathon Marathon @relation(fields: [marathonId], references: [id], onDelete: Cascade) - marathonId Int @map("marathon_id") - persistentIdentifier String? @map("persistent_identifier") - memberships Membership[] - pointEntries PointEntry[] + id Int @id @default(autoincrement()) + uuid String @unique(map: "teams_uuid_unique") @default(uuid()) @db.Uuid + name String + type TeamType + legacyStatus TeamLegacyStatus @map("legacy_status") + marathon Marathon @relation(fields: [marathonId], references: [id], onDelete: Cascade) + marathonId Int @map("marathon_id") + persistentIdentifier String? @map("persistent_identifier") + memberships Membership[] + pointEntries PointEntry[] + correspondingCommittee Committee? @relation(fields: [correspondingCommitteeId], references: [id]) + correspondingCommitteeId Int? @map("committee_id") + + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) @@unique([marathonId, persistentIdentifier], map: "teams_marathon_id_persistent_identifier_key") + @@unique([marathonId, correspondingCommitteeId], map: "teams_marathon_id_committee_id_key") @@index([uuid], map: "teams_uuid") @@map("teams") } +model Committee { + id Int @id @default(autoincrement()) + uuid String @unique(map: "committees_uuid_unique") @default(uuid()) @db.Uuid + identifier CommitteeName + correspondingTeams Team[] + parentCommittee Committee? @relation(fields: [parentCommitteeId], references: [id], name: "parent_committee") + childCommittees Committee[] @relation("parent_committee") + parentCommitteeId Int? @map("parent_committee_id") + + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + + @@index([uuid], map: "committees_uuid") + @@map("committees") +} + view TeamsWithTotalPoints { id Int @id @unique uuid String @unique @db.Uuid From 358376c8a9ceacd45dec0fc41487eb232a74280e Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 3 May 2024 11:30:12 +0000 Subject: [PATCH 034/153] chore: Update CommitteeNode to include identifier field --- packages/common/lib/api/resources/Committee.ts | 11 +++++++++++ .../repositories/committee/CommitteeRespoistory.ts | 0 2 files changed, 11 insertions(+) create mode 100644 packages/server/src/repositories/committee/CommitteeRespoistory.ts diff --git a/packages/common/lib/api/resources/Committee.ts b/packages/common/lib/api/resources/Committee.ts index 709d7408..3b5776f1 100644 --- a/packages/common/lib/api/resources/Committee.ts +++ b/packages/common/lib/api/resources/Committee.ts @@ -1,5 +1,6 @@ import { Field, ID, ObjectType } from "type-graphql"; +import { CommitteeIdentifier } from "../../authorization/structures.js"; import { Node } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -9,6 +10,16 @@ export class CommitteeNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; + @Field(() => CommitteeIdentifier) + identifier!: CommitteeIdentifier; + + static init(init: { id: string; identifier: CommitteeIdentifier }) { + return this.doInit({ + id: init.id, + identifier: init.identifier, + }); + } + public getUniqueId(): string { return this.id; } diff --git a/packages/server/src/repositories/committee/CommitteeRespoistory.ts b/packages/server/src/repositories/committee/CommitteeRespoistory.ts new file mode 100644 index 00000000..e69de29b From 5c42325f76f618e63523a5f6675029b59aec36fb Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 3 May 2024 11:30:16 +0000 Subject: [PATCH 035/153] Add unique index for committees' identifier field --- .../20240427193820_team_committees/migration.sql | 2 ++ .../migration.sql | 8 ++++++++ packages/server/prisma/schema.prisma | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 packages/server/prisma/migrations/20240503111807_add_overall_committee_to_committee_name_enum/migration.sql diff --git a/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql b/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql index f4fe60d4..6e213d2a 100644 --- a/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql +++ b/packages/server/prisma/migrations/20240427193820_team_committees/migration.sql @@ -24,9 +24,11 @@ CREATE TABLE "committees" ( -- CreateIndex CREATE UNIQUE INDEX "committees_uuid_unique" ON "committees"("uuid"); +CREATE UNIQUE INDEX "committees_identifier_unique" ON "committees"("identifier"); -- CreateIndex CREATE INDEX "committees_uuid" ON "committees"("uuid"); +CREATE INDEX "committees_identifier" ON "committees"("identifier"); -- CreateIndex CREATE UNIQUE INDEX "teams_marathon_id_committee_id_key" ON "teams"("marathon_id", "committee_id"); diff --git a/packages/server/prisma/migrations/20240503111807_add_overall_committee_to_committee_name_enum/migration.sql b/packages/server/prisma/migrations/20240503111807_add_overall_committee_to_committee_name_enum/migration.sql new file mode 100644 index 00000000..f24f39c3 --- /dev/null +++ b/packages/server/prisma/migrations/20240503111807_add_overall_committee_to_committee_name_enum/migration.sql @@ -0,0 +1,8 @@ +-- AlterEnum +ALTER TYPE "enum_people_committee_name" ADD VALUE 'overallCommittee'; + +-- DropIndex +DROP INDEX "committees_identifier"; + +-- RenameIndex +ALTER INDEX "committees_identifier_unique" RENAME TO "committees_identifier_key"; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 216b3eb3..d4da53f0 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -255,7 +255,7 @@ model Team { model Committee { id Int @id @default(autoincrement()) uuid String @unique(map: "committees_uuid_unique") @default(uuid()) @db.Uuid - identifier CommitteeName + identifier CommitteeName @unique @map("identifier") correspondingTeams Team[] parentCommittee Committee? @relation(fields: [parentCommitteeId], references: [id], name: "parent_committee") childCommittees Committee[] @relation("parent_committee") @@ -434,6 +434,7 @@ enum CommitteeName { corporateCommittee miniMarathonsCommittee viceCommittee + overallCommittee @@map("enum_people_committee_name") } From 9323f887673031c739fff7223fe25aad63996037 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 3 May 2024 11:30:20 +0000 Subject: [PATCH 036/153] Add overall committee to CommitteeIdentifier and committeeNames --- .../common/lib/authorization/structures.ts | 2 + .../committee/CommitteeRepository.ts | 90 +++++++++++++++++++ .../committee/CommitteeRespoistory.ts | 0 .../committee/committeeDescriptions.ts | 81 +++++++++++++++++ .../committee/committeeRepositoryUtils.ts | 51 +++++++++++ 5 files changed, 224 insertions(+) create mode 100644 packages/server/src/repositories/committee/CommitteeRepository.ts delete mode 100644 packages/server/src/repositories/committee/CommitteeRespoistory.ts create mode 100644 packages/server/src/repositories/committee/committeeDescriptions.ts create mode 100644 packages/server/src/repositories/committee/committeeRepositoryUtils.ts diff --git a/packages/common/lib/authorization/structures.ts b/packages/common/lib/authorization/structures.ts index 991c8bd7..0624b3aa 100644 --- a/packages/common/lib/authorization/structures.ts +++ b/packages/common/lib/authorization/structures.ts @@ -230,6 +230,7 @@ export const CommitteeIdentifier = { corporateCommittee: "corporateCommittee", miniMarathonsCommittee: "miniMarathonsCommittee", viceCommittee: "viceCommittee", + overallCommittee: "overallCommittee", } as const; export type CommitteeIdentifier = (typeof CommitteeIdentifier)[keyof typeof CommitteeIdentifier]; @@ -257,6 +258,7 @@ export const committeeNames: Record = { corporateCommittee: "Corporate Committee", miniMarathonsCommittee: "Mini Marathons Committee", viceCommittee: "Vice Committee", + overallCommittee: "Overall Committee", }; export interface Authorization { diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts new file mode 100644 index 00000000..613cc80f --- /dev/null +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -0,0 +1,90 @@ +import { Prisma, PrismaClient } from "@prisma/client"; +import { CommitteeIdentifier, SortDirection } from "@ukdanceblue/common"; +import { Service } from "typedi"; + +import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { SimpleUniqueParam } from "../shared.js"; + +import * as CommitteeDescriptions from "./committeeDescriptions.js"; +import { + buildCommitteeOrder, + buildCommitteeWhere, +} from "./committeeRepositoryUtils.js"; + +// Make sure that we are exporting a description for every committee +CommitteeDescriptions[ + "" as CommitteeIdentifier +] satisfies Prisma.CommitteeUpsertWithoutChildCommitteesInput; + +const CommitteeOneOfKeys = ["identifier"] as const; +type CommitteeOneOfKeys = (typeof CommitteeOneOfKeys)[number]; + +const CommitteeDateKeys = ["createdAt", "updatedAt"] as const; +type CommitteeDateKey = (typeof CommitteeDateKeys)[number]; + +export type CommitteeFilters = FilterItems< + never, + CommitteeDateKey, + never, + never, + CommitteeOneOfKeys, + never +>; + +type CommitteeUniqueParam = + | SimpleUniqueParam + | { identifier: CommitteeIdentifier }; + +@Service() +export class CommitteeRepository { + constructor(private prisma: PrismaClient) {} + + // Finders + + findCommittees( + filters: readonly CommitteeFilters[] | null | undefined, + order: readonly [key: string, sort: SortDirection][] | null | undefined, + limit?: number | undefined, + offset?: number | undefined + ) { + const where = buildCommitteeWhere(filters); + const orderBy = buildCommitteeOrder(order); + + return this.prisma.committee.findMany({ + where, + orderBy, + take: limit, + skip: offset, + }); + } + + findCommitteeByUnique(param: CommitteeUniqueParam) { + return this.prisma.committee.findUnique({ where: param }); + } + + // Mutators + + deleteCommittee(uuid: string) { + try { + return this.prisma.committee.delete({ where: { uuid } }); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === "P2025" + ) { + return null; + } else { + throw error; + } + } + } + + // Committee getter + + getCommittee(identifier: CommitteeIdentifier) { + return this.prisma.committee.upsert({ + ...CommitteeDescriptions[identifier], + where: { identifier }, + }); + } +} diff --git a/packages/server/src/repositories/committee/CommitteeRespoistory.ts b/packages/server/src/repositories/committee/CommitteeRespoistory.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/server/src/repositories/committee/committeeDescriptions.ts b/packages/server/src/repositories/committee/committeeDescriptions.ts new file mode 100644 index 00000000..bb3300c1 --- /dev/null +++ b/packages/server/src/repositories/committee/committeeDescriptions.ts @@ -0,0 +1,81 @@ +import type { Prisma } from "@prisma/client"; +import { CommitteeIdentifier } from "@ukdanceblue/common"; +export const createCommittee = ( + identifier: CommitteeIdentifier, + parentIdentifier?: CommitteeIdentifier +): Prisma.CommitteeUpsertWithoutChildCommitteesInput => { + const committee: Prisma.CommitteeUpsertWithoutChildCommitteesInput = { + create: { + identifier, + parentCommittee: parentIdentifier + ? { + connect: { + identifier: parentIdentifier, + }, + } + : undefined, + }, + update: { + parentCommittee: parentIdentifier + ? { + connect: { + identifier: parentIdentifier, + }, + } + : undefined, + }, + where: { + identifier, + }, + }; + + return committee; +}; + +export const overallCommittee = createCommittee( + CommitteeIdentifier.overallCommittee +); +export const viceCommittee = createCommittee( + CommitteeIdentifier.viceCommittee, + CommitteeIdentifier.overallCommittee +); +export const fundraisingCommittee = createCommittee( + CommitteeIdentifier.fundraisingCommittee, + CommitteeIdentifier.viceCommittee +); +export const dancerRelationsCommittee = createCommittee( + CommitteeIdentifier.dancerRelationsCommittee, + CommitteeIdentifier.viceCommittee +); +export const marketingCommittee = createCommittee( + CommitteeIdentifier.marketingCommittee, + CommitteeIdentifier.overallCommittee +); +export const corporateCommittee = createCommittee( + CommitteeIdentifier.corporateCommittee, + CommitteeIdentifier.overallCommittee +); +export const techCommittee = createCommittee( + CommitteeIdentifier.techCommittee, + CommitteeIdentifier.overallCommittee +); +export const operationsCommittee = createCommittee( + CommitteeIdentifier.operationsCommittee, + CommitteeIdentifier.overallCommittee +); +export const miniMarathonsCommittee = createCommittee( + CommitteeIdentifier.miniMarathonsCommittee, + CommitteeIdentifier.overallCommittee +); +export const communityDevelopmentCommittee = createCommittee( + CommitteeIdentifier.communityDevelopmentCommittee, + CommitteeIdentifier.overallCommittee +); +export const familyRelationsCommittee = createCommittee( + CommitteeIdentifier.familyRelationsCommittee, + CommitteeIdentifier.overallCommittee +); +export const programmingCommittee = createCommittee( + CommitteeIdentifier.programmingCommittee, + CommitteeIdentifier.overallCommittee +); diff --git a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts new file mode 100644 index 00000000..6ab90af2 --- /dev/null +++ b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts @@ -0,0 +1,51 @@ +import type { Prisma } from "@prisma/client"; +import { SortDirection } from "@ukdanceblue/common"; + +import { + dateFilterToPrisma, + oneOfFilterToPrisma, +} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; + +import type { CommitteeFilters } from "./CommitteeRepository.js"; + +export function buildCommitteeOrder( + order: readonly [key: string, sort: SortDirection][] | null | undefined +) { + const orderBy: Prisma.CommitteeOrderByWithRelationInput = {}; + + for (const [key, sort] of order ?? []) { + switch (key) { + case "identifier": + case "createdAt": + case "updatedAt": { + orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + break; + } + default: { + throw new Error(`Unsupported sort key: ${key}`); + } + } + } + return orderBy; +} + +export function buildCommitteeWhere( + filters: readonly CommitteeFilters[] | null | undefined +) { + const where: Prisma.CommitteeWhereInput = {}; + + for (const filter of filters ?? []) { + switch (filter.field) { + case "identifier": { + where[filter.field] = oneOfFilterToPrisma(filter); + break; + } + case "createdAt": + case "updatedAt": { + where[filter.field] = dateFilterToPrisma(filter); + break; + } + } + } + return where; +} From 573eb576831e1cd25d0f507281eea23f2dadfe16 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 12 May 2024 22:03:27 +0000 Subject: [PATCH 037/153] Update CommitteeRepository to include child and parent committee retrieval methods --- .../committee/CommitteeRepository.ts | 19 ++++ .../membership/MembershipRepository.ts | 103 +++++++++++++++++- .../server/src/resolvers/PersonResolver.ts | 59 ++++++++-- 3 files changed, 169 insertions(+), 12 deletions(-) diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index 613cc80f..e4fe02ca 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -85,6 +85,25 @@ export class CommitteeRepository { return this.prisma.committee.upsert({ ...CommitteeDescriptions[identifier], where: { identifier }, + include: { + correspondingTeams: true, + }, }); } + + getChildCommittees(identifier: CommitteeUniqueParam) { + return this.prisma.committee + .findUnique({ + where: identifier, + }) + .childCommittees(); + } + + getParentCommittee(identifier: CommitteeUniqueParam) { + return this.prisma.committee + .findUnique({ + where: identifier, + }) + .parentCommittee(); + } } diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index ad811218..4f7f5cb4 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,8 +1,12 @@ import { Prisma, PrismaClient } from "@prisma/client"; -import type { SortDirection } from "@ukdanceblue/common"; +import type { + MembershipPositionType, + SortDirection, +} from "@ukdanceblue/common"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { SimpleUniqueParam } from "../shared.js"; import { buildMembershipOrder, @@ -105,6 +109,103 @@ export class MembershipRepository { } } + private async lookupPersonAndTeamId( + personParam: SimpleUniqueParam, + teamParam: SimpleUniqueParam + ) { + let personId, teamId; + if ("id" in personParam) { + personId = personParam.id; + } else if ("uuid" in personParam) { + const found = await this.prisma.person.findUnique({ + where: { uuid: personParam.uuid }, + select: { id: true }, + }); + if (found == null) { + return null; + } + personId = found.id; + } else { + // teamParam satisfies Record; + throw new Error("Must provide either UUID or ID"); + } + if ("id" in teamParam) { + teamId = teamParam.id; + } else if ("uuid" in teamParam) { + const found = await this.prisma.team.findUnique({ + where: teamParam, + select: { id: true }, + }); + if (found == null) { + return null; + } + teamId = found.id; + } else { + teamParam satisfies Record; + throw new Error("Must provide either UUID or ID"); + } + + return { personId, teamId }; + } + + async assignPersonToTeam( + personParam: SimpleUniqueParam, + teamParam: SimpleUniqueParam, + position: MembershipPositionType + ) { + const result = await this.lookupPersonAndTeamId(personParam, teamParam); + if (result == null) { + return null; + } + const { personId, teamId } = result; + + return this.prisma.membership.upsert({ + where: { + personId_teamId: { + personId, + teamId, + }, + team: { + correspondingCommitteeId: null, + }, + }, + create: { + person: { + connect: { + id: personId, + }, + }, + team: { + connect: { + id: teamId, + }, + }, + position, + }, + update: {}, + }); + } + + async removePersonFromTeam( + personParam: SimpleUniqueParam, + teamParam: SimpleUniqueParam + ) { + const result = await this.lookupPersonAndTeamId(personParam, teamParam); + if (result == null) { + return null; + } + const { personId, teamId } = result; + + return this.prisma.membership.delete({ + where: { + personId_teamId: { + personId, + teamId, + }, + }, + }); + } + deleteMembership(param: UniqueMembershipParam) { try { return this.prisma.membership.delete({ where: param }); diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 0f2cbac5..c092da14 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -28,6 +28,7 @@ import { import { Service } from "typedi"; import { auditLogger } from "../lib/logging/auditLogging.js"; +import type { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { membershipModelToResource } from "../repositories/membership/membershipModelToResource.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; @@ -38,7 +39,7 @@ import { AbstractGraphQLOkResponse, AbstractGraphQLPaginatedResponse, } from "./ApiResponse.js"; -import * as Context from "./context.js"; +import type { GraphQLContext } from "./context.js"; @ObjectType("CreatePersonResponse", { implements: AbstractGraphQLCreatedResponse, @@ -54,6 +55,13 @@ class GetPersonResponse extends AbstractGraphQLOkResponse { @Field(() => PersonNode, { nullable: true }) data!: PersonNode | null; } +@ObjectType("GetMembershipResponse", { + implements: AbstractGraphQLOkResponse, +}) +class GetMembershipResponse extends AbstractGraphQLOkResponse { + @Field(() => MembershipNode, { nullable: true }) + data!: MembershipNode | null; +} @ObjectType("GetPeopleResponse", { implements: AbstractGraphQLArrayOkResponse, }) @@ -137,7 +145,10 @@ class SetPersonInput { @Resolver(() => PersonNode) @Service() export class PersonResolver { - constructor(private personRepository: PersonRepository) {} + constructor( + private readonly personRepository: PersonRepository, + private readonly membershipRepository: MembershipRepository + ) {} @Query(() => GetPersonResponse, { name: "person" }) async getByUuid(@Arg("uuid") uuid: string): Promise { @@ -203,12 +214,13 @@ export class PersonResolver { } @Query(() => GetPersonResponse, { name: "me" }) - me(@Ctx() ctx: Context.GraphQLContext): GetPersonResponse | null { + me(@Ctx() ctx: GraphQLContext): GetPersonResponse | null { return GetPersonResponse.newOk( ctx.authenticatedUser ); } + @AccessControl({ accessLevel: AccessLevel.Committee }) @Query(() => GetPeopleResponse, { name: "searchPeopleByName" }) async searchByName(@Arg("name") name: string): Promise { const rows = await this.personRepository.searchByName(name); @@ -218,7 +230,7 @@ export class PersonResolver { ); } - @AccessControl({ accessLevel: AccessLevel.Committee }) + @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => CreatePersonResponse, { name: "createPerson" }) async create( @Arg("input") input: CreatePersonInput @@ -227,8 +239,6 @@ export class PersonResolver { name: input.name, email: input.email, linkblue: input.linkblue, - committeeRole: input.role?.committeeRole, - committeeName: input.role?.committeeIdentifier, }); return CreatePersonResponse.newCreated( @@ -237,7 +247,7 @@ export class PersonResolver { ); } - @AccessControl({ accessLevel: AccessLevel.Committee }) + @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => GetPersonResponse, { name: "setPerson" }) async set( @Arg("uuid") id: string, @@ -251,8 +261,6 @@ export class PersonResolver { name: input.name, email: input.email, linkblue: input.linkblue, - committeeRole: input.role?.committeeRole, - committeeName: input.role?.committeeIdentifier, memberOf: input.memberOf?.map((uuid) => ({ uuid })), captainOf: input.captainOf?.map((uuid) => ({ uuid })), } @@ -269,7 +277,36 @@ export class PersonResolver { ); } - @AccessControl({ accessLevel: AccessLevel.Committee }) + @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) + @Mutation(() => GetMembershipResponse, { name: "addPersonToTeam" }) + async assignPersonToTeam( + @Arg("personUuid") personUuid: string, + @Arg("teamUuid") teamUuid: string + ): Promise { + const membership = await this.membershipRepository.assignPersonToTeam( + { + uuid: personUuid, + }, + { + uuid: teamUuid, + }, + MembershipPositionType.Member + ); + + if (membership == null) { + return GetMembershipResponse.newOk< + MembershipNode | null, + GetMembershipResponse + >(null); + } + + return GetMembershipResponse.newOk< + MembershipNode | null, + GetMembershipResponse + >(membershipModelToResource(membership)); + } + + @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => DeletePersonResponse, { name: "deletePerson" }) async delete(@Arg("uuid") uuid: string): Promise { const result = await this.personRepository.deletePerson({ uuid }); @@ -313,7 +350,7 @@ export class PersonResolver { return models.map((row) => membershipModelToResource(row)); } - @AccessControl({ accessLevel: AccessLevel.Committee }) + @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @FieldResolver(() => [MembershipNode], { deprecationReason: "Use teams instead and filter by position", }) From 3a1b2d0bee509c43f779333d464107e3d51acb0d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 12 May 2024 22:14:15 +0000 Subject: [PATCH 038/153] Update MarathonRepository and TeamRepository to use UniqueMarathonParam --- .../marathon/MarathonRepository.ts | 5 +++- .../src/repositories/team/TeamRepository.ts | 20 +++++++++++-- .../repositories/team/teamModelToResource.ts | 11 +++++-- packages/server/src/resolvers/TeamResolver.ts | 29 +++++++++---------- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 5cbae147..b59f954b 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -49,7 +49,10 @@ export type MarathonFilters = FilterItems< >; // type UniqueParam = { id: number } | { uuid: string }; -type UniqueMarathonParam = { id: number } | { uuid: string } | { year: string }; +export type UniqueMarathonParam = + | { id: number } + | { uuid: string } + | { year: string }; @Service() export class MarathonRepository { diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index da65ec73..1a1e8224 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -8,6 +8,7 @@ import { TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import { buildTeamOrder, buildTeamWhere } from "./teamRepositoryUtils.js"; @@ -204,8 +205,23 @@ export class TeamRepository { }); } - createTeam(data: Prisma.TeamCreateInput) { - return this.prisma.team.create({ data }); + createTeam( + data: { + name: string; + type: TeamType; + legacyStatus: TeamLegacyStatus; + persistentIdentifier?: string | null | undefined; + }, + marathon: UniqueMarathonParam + ) { + return this.prisma.team.create({ + data: { + ...data, + marathon: { + connect: marathon, + }, + }, + }); } updateTeam(param: SimpleUniqueParam, data: Prisma.TeamUpdateInput) { diff --git a/packages/server/src/repositories/team/teamModelToResource.ts b/packages/server/src/repositories/team/teamModelToResource.ts index 3209fcc4..92064779 100644 --- a/packages/server/src/repositories/team/teamModelToResource.ts +++ b/packages/server/src/repositories/team/teamModelToResource.ts @@ -1,7 +1,14 @@ -import type { Team } from "@prisma/client"; +import type { TeamLegacyStatus, TeamType } from "@ukdanceblue/common"; import { TeamNode } from "@ukdanceblue/common"; -export function teamModelToResource(teamModel: Team): TeamNode { +export function teamModelToResource(teamModel: { + uuid: string; + name: string; + type: TeamType; + legacyStatus: TeamLegacyStatus; + createdAt: Date; + updatedAt: Date; +}): TeamNode { return TeamNode.init({ id: teamModel.uuid, name: teamModel.name, diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index b6abf2ba..be106e11 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -134,7 +134,7 @@ class ListTeamsArgs extends FilteredListQueryArgs< visibility!: [DbRole] | null; @Field(() => [String], { nullable: true }) - marathonYear!: [MarathonYearString] | null; + marathonYear!: MarathonYearString[] | null; } @Resolver(() => TeamNode) @@ -175,14 +175,14 @@ export class TeamResolver { take: query.pageSize, onlyDemo: ctx.userData.authSource === AuthSource.Demo, legacyStatus: query.legacyStatus, - marathon: query.marathonYear, + marathon: query.marathonYear?.map((year) => ({ year })), type: query.type, }), this.teamRepository.countTeams({ filters: query.filters, onlyDemo: ctx.userData.authSource === AuthSource.Demo, legacyStatus: query.legacyStatus, - marathonYear: query.marathonYear, + marathon: query.marathonYear?.map((year) => ({ year })), type: query.type, }), ]); @@ -190,12 +190,9 @@ export class TeamResolver { return ListTeamsResponse.newPaginated({ data: rows.map((row) => teamModelToResource({ - id: row.id, uuid: row.uuid, name: row.name, - persistentIdentifier: row.persistentIdentifier, legacyStatus: row.legacyStatus, - marathonYear: row.marathonYear, type: row.type, updatedAt: row.updatedAt, createdAt: row.createdAt, @@ -223,15 +220,18 @@ export class TeamResolver { ) @Mutation(() => CreateTeamResponse, { name: "createTeam" }) async create( - @Arg("input") input: CreateTeamInput + @Arg("input") input: CreateTeamInput, + @Arg("marathon") marathonUuid: string ): Promise { - const row = await this.teamRepository.createTeam({ - name: input.name, - type: input.type, - legacyStatus: input.legacyStatus, - marathonYear: input.marathonYear, - persistentIdentifier: input.persistentIdentifier, - }); + const row = await this.teamRepository.createTeam( + { + name: input.name, + type: input.type, + legacyStatus: input.legacyStatus, + persistentIdentifier: input.persistentIdentifier, + }, + { uuid: marathonUuid } + ); return CreateTeamResponse.newCreated(teamModelToResource(row), row.uuid); } @@ -262,7 +262,6 @@ export class TeamResolver { name: input.name ?? undefined, type: input.type ?? undefined, legacyStatus: input.legacyStatus ?? undefined, - marathonYear: input.marathonYear ?? undefined, persistentIdentifier: input.persistentIdentifier, } ); From 7129dc0b91ce8595e7d1d3dcfbc1c4e3b73bea5a Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 14 May 2024 22:08:25 +0000 Subject: [PATCH 039/153] Update database schema for optional marathon date and committee role on membership --- .../migration.sql | 13 + .../migration.sql | 3 + packages/server/prisma/schema.prisma | 49 +- .../repositories/person/PersonRepository.ts | 28 +- .../server/src/resolvers/PersonResolver.ts | 28 +- schema.graphql | 483 ++++++++---------- 6 files changed, 303 insertions(+), 301 deletions(-) create mode 100644 packages/server/prisma/migrations/20240513003536_committee_role_on_membership/migration.sql create mode 100644 packages/server/prisma/migrations/20240514220651_optional_marathon_date/migration.sql diff --git a/packages/server/prisma/migrations/20240513003536_committee_role_on_membership/migration.sql b/packages/server/prisma/migrations/20240513003536_committee_role_on_membership/migration.sql new file mode 100644 index 00000000..d747c83d --- /dev/null +++ b/packages/server/prisma/migrations/20240513003536_committee_role_on_membership/migration.sql @@ -0,0 +1,13 @@ +/* + Warnings: + + - You are about to drop the column `committee_name` on the `people` table. All the data in the column will be lost. + - You are about to drop the column `committee_role` on the `people` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "memberships" ADD COLUMN "committee_role" "enum_people_committee_role"; + +-- AlterTable +ALTER TABLE "people" DROP COLUMN "committee_name", +DROP COLUMN "committee_role"; diff --git a/packages/server/prisma/migrations/20240514220651_optional_marathon_date/migration.sql b/packages/server/prisma/migrations/20240514220651_optional_marathon_date/migration.sql new file mode 100644 index 00000000..2276edb9 --- /dev/null +++ b/packages/server/prisma/migrations/20240514220651_optional_marathon_date/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "marathons" ALTER COLUMN "start_date" DROP NOT NULL, +ALTER COLUMN "end_date" DROP NOT NULL; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index d4da53f0..b28a846b 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -150,15 +150,16 @@ model LoginFlowSession { } model Membership { - id Int @id @default(autoincrement()) - uuid String @unique(map: "memberships_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - personId Int @map("person_id") - teamId Int @map("team_id") - position MembershipPosition - person Person @relation(fields: [personId], references: [id], onDelete: Cascade) - team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + id Int @id @default(autoincrement()) + uuid String @unique(map: "memberships_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + personId Int @map("person_id") + teamId Int @map("team_id") + committeeRole CommitteeRole? @map("committee_role") + position MembershipPosition + person Person @relation(fields: [personId], references: [id], onDelete: Cascade) + team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([personId, teamId], map: "memberships_person_id_team_id_key") @@index([uuid], map: "memberships_uuid") @@ -166,20 +167,18 @@ model Membership { } model Person { - id Int @id @default(autoincrement()) - uuid String @unique(map: "people_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - name String? - email String @unique(map: "people_email_unique") - linkblue String? @unique(map: "people_linkblue_unique") - committeeRole CommitteeRole? @map("committee_role") - committeeName CommitteeName? @map("committee_name") - authIdPairs AuthIdPair[] - devices Device[] - memberships Membership[] - pointEntries PointEntry[] - ownedFiles File[] + id Int @id @default(autoincrement()) + uuid String @unique(map: "people_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + name String? + email String @unique(map: "people_email_unique") + linkblue String? @unique(map: "people_linkblue_unique") + authIdPairs AuthIdPair[] + devices Device[] + memberships Membership[] + pointEntries PointEntry[] + ownedFiles File[] @@index([uuid], map: "people_uuid") @@map("people") @@ -344,8 +343,8 @@ model Marathon { createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) year String @unique - startDate DateTime @map("start_date") @db.Timestamptz(6) - endDate DateTime @map("end_date") @db.Timestamptz(6) + startDate DateTime? @map("start_date") @db.Timestamptz(6) + endDate DateTime? @map("end_date") @db.Timestamptz(6) hours MarathonHour[] teams Team[] teamsWithTotalPoints TeamsWithTotalPoints[] diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 3483ac44..b1cbf7ac 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -2,7 +2,6 @@ import type { Person } from "@prisma/client"; import { Prisma, PrismaClient } from "@prisma/client"; import { AuthSource, - CommitteeIdentifier, CommitteeRole, DbRole, DetailedError, @@ -177,17 +176,20 @@ export class PersonRepository { async findMembershipsOfPerson( param: { uuid: string } | { id: number }, - opts: { - position?: MembershipPositionType; - } = {} + opts: + | { + position: MembershipPositionType; + } + | { + committeeRole: CommitteeRole; + } + | Record = {} ) { const rows = await this.prisma.person.findUnique({ where: param, select: { memberships: { - where: { - position: opts.position, - }, + where: opts, }, }, }); @@ -201,15 +203,11 @@ export class PersonRepository { name, email, linkblue, - committeeRole, - committeeName, authIds, }: { name?: string | null; email: string; linkblue?: string | null; - committeeRole?: CommitteeRole | null; - committeeName?: CommitteeIdentifier | null; authIds?: { source: Exclude; value: string }[] | null; }): Promise { return this.prisma.person.create({ @@ -217,8 +215,6 @@ export class PersonRepository { name, email, linkblue, - committeeRole, - committeeName, authIdPairs: authIds ? { createMany: { @@ -242,8 +238,6 @@ export class PersonRepository { name, email, linkblue, - committeeRole, - committeeName, authIds, memberOf, captainOf, @@ -251,8 +245,6 @@ export class PersonRepository { name?: string | undefined | null; email?: string | undefined; linkblue?: string | undefined | null; - committeeRole?: CommitteeRole | undefined | null; - committeeName?: CommitteeIdentifier | undefined | null; authIds?: | { source: Exclude; value: string }[] | undefined @@ -311,8 +303,6 @@ export class PersonRepository { name, email, linkblue, - committeeRole, - committeeName, authIdPairs: authIds ? { upsert: authIds.map((authId) => { diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index c092da14..f9bb6e07 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -326,6 +326,30 @@ export class PersonResolver { return DeletePersonResponse.newOk(true); } + @AccessControl( + { accessLevel: AccessLevel.Committee }, + { + rootMatch: [ + { + root: "uuid", + extractor: (userData) => userData.userId, + }, + ], + } + ) + @FieldResolver(() => [MembershipNode]) + async committees(@Root() person: PersonNode): Promise { + const models = await this.personRepository.findMembershipsOfPerson({ + uuid: person.id, + }); + + if (models == null) { + return []; + } + + return models.map((row) => membershipModelToResource(row)); + } + @AccessControl( { accessLevel: AccessLevel.Committee }, { @@ -356,7 +380,9 @@ export class PersonResolver { }) async captaincies(@Root() person: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson( - { uuid: person.id }, + { + uuid: person.id, + }, { position: MembershipPositionType.Captain } ); diff --git a/schema.graphql b/schema.graphql index 28d13702..99c18990 100644 --- a/schema.graphql +++ b/schema.graphql @@ -44,15 +44,10 @@ type AcknowledgeDeliveryIssueResponse implements AbstractGraphQLOkResponse & Gra } type AddEventImageResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: ImageResource! + data: ImageNode! ok: Boolean! } -type AuthIdPairResource { - source: AuthSource! - value: String! -} - """The source of authentication""" enum AuthSource { Anonymous @@ -61,47 +56,25 @@ enum AuthSource { None } -"""The identifier for a committee""" -enum CommitteeIdentifier { - communityDevelopmentCommittee - corporateCommittee - dancerRelationsCommittee - familyRelationsCommittee - fundraisingCommittee - marketingCommittee - miniMarathonsCommittee - operationsCommittee - programmingCommittee - techCommittee - viceCommittee -} - -"""Roles within a committee""" -enum CommitteeRole { - Chair - Coordinator - Member -} - -type ConfigurationResource { +type ConfigurationNode implements Node { createdAt: DateTimeISO + id: ID! key: String! updatedAt: DateTimeISO - uuid: ID! - validAfter: LuxonDateTime - validUntil: LuxonDateTime + validAfter: DateTimeISO + validUntil: DateTimeISO value: String! } input CreateConfigurationInput { key: String! - validAfter: LuxonDateTime - validUntil: LuxonDateTime + validAfter: DateTimeISO + validUntil: DateTimeISO value: String! } type CreateConfigurationResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: ConfigurationResource! + data: ConfigurationNode! ok: Boolean! uuid: String! } @@ -116,11 +89,11 @@ input CreateEventInput { input CreateEventOccurrenceInput { fullDay: Boolean! - interval: LuxonDateRange! + interval: IntervalISOInput! } type CreateEventResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: EventResource! + data: EventNode! ok: Boolean! uuid: String! } @@ -151,15 +124,15 @@ input CreateMarathonInput { input CreatePersonInput { captainOf: [String!]! = [] + dbRole: DbRole email: EmailAddress! linkblue: String memberOf: [String!]! = [] name: String - role: RoleResourceInput } type CreatePersonResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PersonResource! + data: PersonNode! ok: Boolean! uuid: String! } @@ -173,7 +146,7 @@ input CreatePointEntryInput { } type CreatePointEntryResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PointEntryResource! + data: PointEntryNode! ok: Boolean! uuid: String! } @@ -181,12 +154,12 @@ type CreatePointEntryResponse implements AbstractGraphQLCreatedResponse & Abstra input CreatePointOpportunityInput { eventUuid: ID name: String! - opportunityDate: LuxonDateTime + opportunityDate: DateTimeISO type: TeamType! } type CreatePointOpportunityResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PointOpportunityResource! + data: PointOpportunityNode! ok: Boolean! uuid: String! } @@ -200,7 +173,7 @@ input CreateTeamInput { } type CreateTeamResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: TeamResource! + data: TeamNode! ok: Boolean! uuid: String! } @@ -255,6 +228,23 @@ type DeleteTeamResponse implements AbstractGraphQLOkResponse & GraphQLBaseRespon ok: Boolean! } +type DeviceNode implements Node { + createdAt: DateTimeISO + id: ID! + lastLoggedInUser: PersonNode + lastLogin: DateTimeISO + notificationDeliveries( + page: Int = 1 + pageSize: Int = 10 + + """ + The verifier code for this device, if it does not match then the query will be rejected + """ + verifier: String + ): [NotificationDeliveryNode!]! + updatedAt: DateTimeISO +} + enum DeviceResolverAllKeys { createdAt expoPushToken @@ -279,7 +269,7 @@ input DeviceResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input DeviceResolverKeyedIsNullFilterItem { @@ -321,32 +311,26 @@ enum DeviceResolverStringFilterKeys { expoPushToken } -type DeviceResource { - createdAt: DateTimeISO - expoPushToken: String - lastLoggedInUser: PersonResource - lastLogin: LuxonDateTime - notificationDeliveries( - page: Int = 1 - pageSize: Int = 10 - - """ - The verifier code for this device, if it does not match then the query will be rejected - """ - verifier: String - ): [NotificationDeliveryResource!]! - updatedAt: DateTimeISO - uuid: ID! -} - """ A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. """ scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") -type EventOccurrenceResource { +type EventNode implements Node { + createdAt: DateTimeISO + description: String + id: ID! + images: [ImageNode!]! + location: String + occurrences: [EventOccurrenceNode!]! + summary: String + title: String! + updatedAt: DateTimeISO +} + +type EventOccurrenceNode { fullDay: Boolean! - interval: LuxonDateRange! + interval: IntervalISO! uuid: ID! } @@ -381,7 +365,7 @@ input EventResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input EventResolverKeyedIsNullFilterItem { @@ -426,69 +410,62 @@ enum EventResolverStringFilterKeys { title } -type EventResource { +type FeedNode implements Node { createdAt: DateTimeISO - description: String - images: [ImageResource!]! - location: String - occurrences: [EventOccurrenceResource!]! - summary: String - title: String! - updatedAt: DateTimeISO - uuid: ID! -} - -type FeedResource { - createdAt: DateTimeISO - image: ImageResource + id: ID! + image: ImageNode textContent: String title: String! updatedAt: DateTimeISO - uuid: ID! } type GetAllConfigurationsResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { - data: [ConfigurationResource!]! + data: [ConfigurationNode!]! ok: Boolean! } type GetConfigurationByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: ConfigurationResource! + data: ConfigurationNode! ok: Boolean! } type GetDeviceByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: DeviceResource! + data: DeviceNode! ok: Boolean! } type GetEventByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: EventResource! + data: EventNode! ok: Boolean! } type GetImageByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: ImageResource! + data: ImageNode! + ok: Boolean! +} + +type GetMembershipResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { + data: MembershipNode ok: Boolean! } type GetNotificationByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: NotificationResource! + data: NotificationNode! ok: Boolean! } type GetPeopleResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { - data: [PersonResource!]! + data: [PersonNode!]! ok: Boolean! } type GetPersonResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PersonResource + data: PersonNode ok: Boolean! } type GetPointEntryByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PointEntryResource! + data: PointEntryNode! ok: Boolean! } @@ -497,6 +474,18 @@ interface GraphQLBaseResponse { ok: Boolean! } +type ImageNode implements Node { + alt: String + createdAt: DateTimeISO + height: Int! + id: ID! + mimeType: String! + thumbHash: String + updatedAt: DateTimeISO + url: URL + width: Int! +} + enum ImageResolverAllKeys { alt createdAt @@ -521,7 +510,7 @@ input ImageResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input ImageResolverKeyedIsNullFilterItem { @@ -582,20 +571,18 @@ enum ImageResolverStringFilterKeys { alt } -type ImageResource { - alt: String - createdAt: DateTimeISO - height: Int! - mimeType: String! - thumbHash: String - updatedAt: DateTimeISO - url: URL - uuid: ID! - width: Int! +type IntervalISO { + end: DateTimeISO! + start: DateTimeISO! +} + +input IntervalISOInput { + end: DateTimeISO! + start: DateTimeISO! } type ListDevicesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [DeviceResource!]! + data: [DeviceNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -609,7 +596,7 @@ type ListDevicesResponse implements AbstractGraphQLArrayOkResponse & AbstractGra } type ListEventsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [EventResource!]! + data: [EventNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -623,7 +610,7 @@ type ListEventsResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap } type ListImagesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [ImageResource!]! + data: [ImageNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -637,7 +624,7 @@ type ListImagesResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap } type ListMarathonsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [MarathonResource!]! + data: [MarathonNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -651,7 +638,7 @@ type ListMarathonsResponse implements AbstractGraphQLArrayOkResponse & AbstractG } type ListNotificationDeliveriesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [NotificationDeliveryResource!]! + data: [NotificationDeliveryNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -665,7 +652,7 @@ type ListNotificationDeliveriesResponse implements AbstractGraphQLArrayOkRespons } type ListNotificationsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [NotificationResource!]! + data: [NotificationNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -679,7 +666,7 @@ type ListNotificationsResponse implements AbstractGraphQLArrayOkResponse & Abstr } type ListPeopleResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [PersonResource!]! + data: [PersonNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -693,7 +680,7 @@ type ListPeopleResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap } type ListPointEntriesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [PointEntryResource!]! + data: [PointEntryNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -707,7 +694,7 @@ type ListPointEntriesResponse implements AbstractGraphQLArrayOkResponse & Abstra } type ListPointOpportunitiesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [PointOpportunityResource!]! + data: [PointOpportunityNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -721,7 +708,7 @@ type ListPointOpportunitiesResponse implements AbstractGraphQLArrayOkResponse & } type ListTeamsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { - data: [TeamResource!]! + data: [TeamNode!]! ok: Boolean! """The current page number (1-indexed)""" @@ -736,25 +723,29 @@ type ListTeamsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraph type LoginState { authSource: AuthSource! + dbRole: DbRole! loggedIn: Boolean! - role: RoleResource! } -"""Date range custom scalar type (just an ISO 8601 interval)""" -scalar LuxonDateRange @specifiedBy(url: "https://www.iso.org/iso-8601-date-and-time-format.html") - -"""Luxon DateTime custom scalar type""" -scalar LuxonDateTime - -type MarathonHourResource { +type MarathonHourNode implements Node { createdAt: DateTimeISO details: String durationInfo: String! - mapImages: [ImageResource!]! + id: ID! + mapImages: [ImageNode!]! shownStartingAt: DateTimeISO! title: String! updatedAt: DateTimeISO - uuid: ID! +} + +type MarathonNode implements Node { + createdAt: DateTimeISO + endDate: DateTimeISO! + hours: [MarathonHourNode!]! + id: ID! + startDate: DateTimeISO! + updatedAt: DateTimeISO + year: String! } enum MarathonResolverAllKeys { @@ -783,7 +774,7 @@ input MarathonResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input MarathonResolverKeyedIsNullFilterItem { @@ -796,14 +787,13 @@ input MarathonResolverKeyedIsNullFilterItem { negate: Boolean = false } -type MarathonResource { +type MembershipNode implements Node { createdAt: DateTimeISO - endDate: DateTimeISO! - hours: [MarathonHourResource!]! - startDate: DateTimeISO! + id: ID! + person: PersonNode! + position: MembershipPositionType! + team: TeamNode! updatedAt: DateTimeISO - uuid: ID! - year: String! } """The position of a member on a team""" @@ -812,32 +802,24 @@ enum MembershipPositionType { Member } -type MembershipResource { - createdAt: DateTimeISO - person: PersonResource! - position: MembershipPositionType! - team: TeamResource! - updatedAt: DateTimeISO - uuid: ID! -} - type Mutation { abortScheduledNotification(uuid: String!): AbortScheduledNotificationResponse! acknowledgeDeliveryIssue(uuid: String!): AcknowledgeDeliveryIssueResponse! addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! - addMap(imageUuid: String!, uuid: String!): MarathonHourResource! - attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedResource! + addMap(imageUuid: String!, uuid: String!): MarathonHourNode! + addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! + attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! createConfiguration(input: CreateConfigurationInput!): CreateConfigurationResponse! createConfigurations(input: [CreateConfigurationInput!]!): CreateConfigurationResponse! createEvent(input: CreateEventInput!): CreateEventResponse! - createFeedItem(input: CreateFeedInput!): FeedResource! - createImage(input: CreateImageInput!): ImageResource! - createMarathon(input: CreateMarathonInput!): MarathonResource! - createMarathonHour(input: CreateMarathonHourInput!, marathonUuid: String!): MarathonHourResource! + createFeedItem(input: CreateFeedInput!): FeedNode! + createImage(input: CreateImageInput!): ImageNode! + createMarathon(input: CreateMarathonInput!): MarathonNode! + createMarathonHour(input: CreateMarathonHourInput!, marathonUuid: String!): MarathonHourNode! createPerson(input: CreatePersonInput!): CreatePersonResponse! createPointEntry(input: CreatePointEntryInput!): CreatePointEntryResponse! createPointOpportunity(input: CreatePointOpportunityInput!): CreatePointOpportunityResponse! - createTeam(input: CreateTeamInput!): CreateTeamResponse! + createTeam(input: CreateTeamInput!, marathon: String!): CreateTeamResponse! deleteConfiguration(uuid: String!): DeleteConfigurationResponse! deleteDevice(uuid: String!): DeleteDeviceResponse! deleteEvent(uuid: String!): DeleteEventResponse! @@ -858,24 +840,28 @@ type Mutation { deleteTeam(uuid: String!): DeleteTeamResponse! registerDevice(input: RegisterDeviceInput!): RegisterDeviceResponse! removeImageFromEvent(eventId: String!, imageId: String!): RemoveEventImageResponse! - removeImageFromFeedItem(feedItemUuid: String!): FeedResource! + removeImageFromFeedItem(feedItemUuid: String!): FeedNode! removeMap(imageUuid: String!, uuid: String!): Void! scheduleNotification(sendAt: DateTimeISO!, uuid: String!): ScheduleNotificationResponse! """Send a notification immediately.""" sendNotification(uuid: String!): SendNotificationResponse! setEvent(input: SetEventInput!, uuid: String!): SetEventResponse! - setFeedItem(feedItemUuid: String!, input: SetFeedInput!): FeedResource! - setImageAltText(alt: String!, uuid: String!): ImageResource! - setImageUrl(uuid: String!): ImageResource! - setMarathon(input: SetMarathonInput!, uuid: String!): MarathonResource! - setMarathonHour(input: SetMarathonHourInput!, uuid: String!): MarathonHourResource! + setFeedItem(feedItemUuid: String!, input: SetFeedInput!): FeedNode! + setImageAltText(alt: String!, uuid: String!): ImageNode! + setImageUrl(uuid: String!): ImageNode! + setMarathon(input: SetMarathonInput!, uuid: String!): MarathonNode! + setMarathonHour(input: SetMarathonHourInput!, uuid: String!): MarathonHourNode! setPerson(input: SetPersonInput!, uuid: String!): GetPersonResponse! setPointOpportunity(input: SetPointOpportunityInput!, uuid: String!): SinglePointOpportunityResponse! setTeam(input: SetTeamInput!, uuid: String!): SingleTeamResponse! stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! } +interface Node { + id: ID! +} + """Integers that will have a value of 0 or more.""" scalar NonNegativeInt @@ -896,6 +882,26 @@ type NotificationDeliveryIssueCount { Unknown: Int! } +type NotificationDeliveryNode implements Node { + """ + A unique identifier corresponding the group of notifications this was sent to Expo with. + """ + chunkUuid: String + createdAt: DateTimeISO + + """Any error message returned by Expo when sending the notification.""" + deliveryError: String + id: ID! + notification: NotificationNode! + + """The time the server received a delivery receipt from the user.""" + receiptCheckedAt: DateTimeISO + + """The time the server sent the notification to Expo for delivery.""" + sentAt: DateTimeISO + updatedAt: DateTimeISO +} + enum NotificationDeliveryResolverAllKeys { createdAt deliveryError @@ -922,7 +928,7 @@ input NotificationDeliveryResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input NotificationDeliveryResolverKeyedIsNullFilterItem { @@ -935,24 +941,25 @@ input NotificationDeliveryResolverKeyedIsNullFilterItem { negate: Boolean = false } -type NotificationDeliveryResource { - """ - A unique identifier corresponding the group of notifications this was sent to Expo with. - """ - chunkUuid: String +type NotificationNode implements Node { + body: String! createdAt: DateTimeISO + deliveryCount: Int! + deliveryIssue: String + deliveryIssueAcknowledgedAt: DateTimeISO + deliveryIssueCount: NotificationDeliveryIssueCount! + id: ID! - """Any error message returned by Expo when sending the notification.""" - deliveryError: String - notification: NotificationResource! - - """The time the server received a delivery receipt from the user.""" - receiptCheckedAt: DateTimeISO + """ + The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. + """ + sendAt: DateTimeISO - """The time the server sent the notification to Expo for delivery.""" - sentAt: DateTimeISO + """The time the server started sending the notification.""" + startedSendingAt: DateTimeISO + title: String! updatedAt: DateTimeISO - uuid: ID! + url: URL } enum NotificationResolverAllKeys { @@ -983,7 +990,7 @@ input NotificationResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input NotificationResolverKeyedIsNullFilterItem { @@ -1030,27 +1037,6 @@ enum NotificationResolverStringFilterKeys { title } -type NotificationResource { - body: String! - createdAt: DateTimeISO - deliveryCount: Int! - deliveryIssue: String - deliveryIssueAcknowledgedAt: DateTimeISO - deliveryIssueCount: NotificationDeliveryIssueCount! - - """ - The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. - """ - sendAt: DateTimeISO - - """The time the server started sending the notification.""" - startedSendingAt: DateTimeISO - title: String! - updatedAt: DateTimeISO - url: URL - uuid: ID! -} - enum NumericComparator { EQUALS GREATER_THAN @@ -1060,6 +1046,18 @@ enum NumericComparator { LESS_THAN_OR_EQUAL_TO } +type PersonNode implements Node { + captaincies: [MembershipNode!]! @deprecated(reason: "Use teams instead and filter by position") + createdAt: DateTimeISO + dbRole: DbRole! + email: String! + id: ID! + linkblue: String + name: String + teams: [MembershipNode!]! + updatedAt: DateTimeISO +} + enum PersonResolverAllKeys { committeeName committeeRole @@ -1116,17 +1114,15 @@ enum PersonResolverStringFilterKeys { name } -type PersonResource { - authIds: [AuthIdPairResource!]! @deprecated(reason: "This is now provided on the AuthIdPair resource.") - captaincies: [MembershipResource!]! @deprecated(reason: "Use teams instead and filter by position") +type PointEntryNode implements Node { + comment: String createdAt: DateTimeISO - email: String! - linkblue: String - name: String - role: RoleResource! - teams: [MembershipResource!]! + id: ID! + personFrom: PersonNode + pointOpportunity: PointOpportunityNode + points: Int! + team: TeamNode! updatedAt: DateTimeISO - uuid: ID! } enum PointEntryResolverAllKeys { @@ -1150,7 +1146,7 @@ input PointEntryResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input PointEntryResolverKeyedIsNullFilterItem { @@ -1163,15 +1159,14 @@ input PointEntryResolverKeyedIsNullFilterItem { negate: Boolean = false } -type PointEntryResource { - comment: String +type PointOpportunityNode implements Node { createdAt: DateTimeISO - personFrom: PersonResource - pointOpportunity: PointOpportunityResource - points: Int! - team: TeamResource! + event: EventNode + id: ID! + name: String! + opportunityDate: DateTimeISO + type: TeamType! updatedAt: DateTimeISO - uuid: ID! } enum PointOpportunityResolverAllKeys { @@ -1199,7 +1194,7 @@ input PointOpportunityResolverKeyedDateFilterItem { Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. """ negate: Boolean = false - value: LuxonDateTime! + value: DateTimeISO! } input PointOpportunityResolverKeyedIsNullFilterItem { @@ -1245,24 +1240,14 @@ enum PointOpportunityResolverStringFilterKeys { name } -type PointOpportunityResource { - createdAt: DateTimeISO - event: EventResource - name: String! - opportunityDate: LuxonDateTime - type: TeamType! - updatedAt: DateTimeISO - uuid: ID! -} - """Integers that will have a value greater than 0.""" scalar PositiveInt type Query { activeConfiguration(key: String!): GetConfigurationByUuidResponse! allConfigurations: GetAllConfigurationsResponse! - currentMarathon: MarathonResource - currentMarathonHour: MarathonHourResource + currentMarathon: MarathonNode + currentMarathonHour: MarathonHourNode device(uuid: String!): GetDeviceByUuidResponse! devices( """The boolean filters to apply to the query""" @@ -1351,7 +1336,7 @@ type Query { """The string filters to apply to the query""" stringFilters: [EventResolverKeyedStringFilterItem!] ): ListEventsResponse! - feed(limit: Int = 10): [FeedResource!]! + feed(limit: Int = 10): [FeedNode!]! image(uuid: String!): GetImageByUuidResponse! images( """The boolean filters to apply to the query""" @@ -1440,9 +1425,9 @@ type Query { stringFilters: [PersonResolverKeyedStringFilterItem!] ): ListPeopleResponse! loginState: LoginState! - marathon(uuid: String!): MarathonResource! - marathonForYear(year: String!): MarathonResource! - marathonHour(uuid: String!): MarathonHourResource! + marathon(uuid: String!): MarathonNode! + marathonForYear(year: String!): MarathonNode! + marathonHour(uuid: String!): MarathonHourNode! marathons( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1487,7 +1472,7 @@ type Query { stringFilters: Void ): ListMarathonsResponse! me: GetPersonResponse! - nextMarathon: MarathonResource + nextMarathon: MarathonNode notification(uuid: String!): GetNotificationByUuidResponse! notificationDeliveries( """The boolean filters to apply to the query""" @@ -1731,7 +1716,7 @@ input RegisterDeviceInput { } type RegisterDeviceResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: DeviceResource! + data: DeviceNode! ok: Boolean! } @@ -1740,18 +1725,6 @@ type RemoveEventImageResponse implements AbstractGraphQLOkResponse & GraphQLBase ok: Boolean! } -type RoleResource { - committeeIdentifier: CommitteeIdentifier - committeeRole: CommitteeRole - dbRole: DbRole! -} - -input RoleResourceInput { - committeeIdentifier: CommitteeIdentifier - committeeRole: CommitteeRole - dbRole: DbRole! = None -} - type ScheduleNotificationResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { data: Boolean! ok: Boolean! @@ -1772,7 +1745,7 @@ input SetEventInput { input SetEventOccurrenceInput { fullDay: Boolean! - interval: LuxonDateRange! + interval: IntervalISOInput! """ If updating an existing occurrence, the UUID of the occurrence to update @@ -1781,7 +1754,7 @@ input SetEventOccurrenceInput { } type SetEventResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: EventResource! + data: EventNode! ok: Boolean! } @@ -1805,17 +1778,17 @@ input SetMarathonInput { input SetPersonInput { captainOf: [String!] + dbRole: DbRole email: EmailAddress linkblue: String memberOf: [String!] name: String - role: RoleResourceInput } input SetPointOpportunityInput { eventUuid: ID name: String - opportunityDate: LuxonDateTime + opportunityDate: DateTimeISO type: TeamType } @@ -1828,12 +1801,12 @@ input SetTeamInput { } type SinglePointOpportunityResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PointOpportunityResource! + data: PointOpportunityNode! ok: Boolean! } type SingleTeamResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: TeamResource! + data: TeamNode! ok: Boolean! } @@ -1843,7 +1816,7 @@ enum SortDirection { } type StageNotificationResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: NotificationResource! + data: NotificationNode! ok: Boolean! uuid: String! } @@ -1863,6 +1836,19 @@ enum TeamLegacyStatus { ReturningTeam } +type TeamNode implements Node { + captains: [MembershipNode!]! @deprecated(reason: "Just query the members field and filter by role") + createdAt: DateTimeISO + id: ID! + legacyStatus: TeamLegacyStatus! + members: [MembershipNode!]! + name: String! + pointEntries: [PointEntryNode!]! + totalPoints: Int! + type: TeamType! + updatedAt: DateTimeISO +} + enum TeamResolverAllKeys { legacyStatus marathonYear @@ -1915,21 +1901,6 @@ enum TeamResolverStringFilterKeys { name } -type TeamResource { - captains: [MembershipResource!]! @deprecated(reason: "Just query the members field and filter by role") - createdAt: DateTimeISO - legacyStatus: TeamLegacyStatus! - marathonYear: String! - members: [MembershipResource!]! - name: String! - persistentIdentifier: String - pointEntries: [PointEntryResource!]! - totalPoints: Int! - type: TeamType! - updatedAt: DateTimeISO - uuid: ID! -} - """Types of teams""" enum TeamType { Committee From aa16cb2b00f994d7f8b4a86e9d2947198b573dfb Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 14 May 2024 22:22:27 +0000 Subject: [PATCH 040/153] Update MembershipRepository to support assigning person to team with committee role --- .../membership/MembershipRepository.ts | 41 ++++++++++++++++--- .../server/src/resolvers/PersonResolver.ts | 10 ++--- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index 4f7f5cb4..f2e4b478 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,5 +1,6 @@ import { Prisma, PrismaClient } from "@prisma/client"; -import type { +import { + CommitteeRole, MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; @@ -148,17 +149,44 @@ export class MembershipRepository { return { personId, teamId }; } - async assignPersonToTeam( - personParam: SimpleUniqueParam, - teamParam: SimpleUniqueParam, - position: MembershipPositionType - ) { + async assignPersonToTeam({ + personParam, + teamParam, + ...additionalData + }: { + personParam: SimpleUniqueParam; + teamParam: SimpleUniqueParam; + } & ( + | { + position: MembershipPositionType; + } + | { + committeeRole: CommitteeRole; + } + )) { const result = await this.lookupPersonAndTeamId(personParam, teamParam); if (result == null) { return null; } const { personId, teamId } = result; + let position: MembershipPositionType; + let committeeRole: CommitteeRole | undefined; + if ("position" in additionalData) { + // eslint-disable-next-line prefer-destructuring + position = additionalData.position; + } else if ("committeeRole" in additionalData) { + // eslint-disable-next-line prefer-destructuring + committeeRole = additionalData.committeeRole; + position = + additionalData.committeeRole === CommitteeRole.Chair + ? MembershipPositionType.Captain + : MembershipPositionType.Member; + } else { + additionalData satisfies Record; + throw new Error("Must provide either position or committeeRole"); + } + return this.prisma.membership.upsert({ where: { personId_teamId: { @@ -181,6 +209,7 @@ export class MembershipRepository { }, }, position, + committeeRole, }, update: {}, }); diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index f9bb6e07..a6a0c43f 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -283,15 +283,15 @@ export class PersonResolver { @Arg("personUuid") personUuid: string, @Arg("teamUuid") teamUuid: string ): Promise { - const membership = await this.membershipRepository.assignPersonToTeam( - { + const membership = await this.membershipRepository.assignPersonToTeam({ + personParam: { uuid: personUuid, }, - { + teamParam: { uuid: teamUuid, }, - MembershipPositionType.Member - ); + position: MembershipPositionType.Member, + }); if (membership == null) { return GetMembershipResponse.newOk< From e52a633b773cfa7b4d2c1eabb78baa95dbacd367 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 15 May 2024 00:32:48 +0000 Subject: [PATCH 041/153] Update MarathonRepository to order marathons by ascending year --- packages/common/lib/api/resources/Marathon.ts | 20 ++--- .../committee/CommitteeRepository.ts | 77 ++++++++++++++++- .../marathon/MarathonRepository.ts | 2 +- .../membership/MembershipRepository.ts | 82 +------------------ .../src/routes/api/auth/oidcCallback.ts | 2 - packages/server/src/seed.ts | 18 +++- 6 files changed, 99 insertions(+), 102 deletions(-) diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index a835e406..046e05fe 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -14,15 +14,15 @@ export class MarathonNode extends TimestampedResource implements Node { id!: string; @Field(() => String) year!: string; - @Field(() => DateTimeISOResolver) - startDate!: Date; - get startDateDateTime(): DateTime { - return dateTimeFromSomething(this.startDate); + @Field(() => DateTimeISOResolver, { nullable: true }) + startDate?: Date | undefined | null; + get startDateDateTime(): DateTime | null { + return dateTimeFromSomething(this.startDate) ?? null; } - @Field(() => DateTimeISOResolver) - endDate!: Date; - get endDateDateTime(): DateTime { - return dateTimeFromSomething(this.endDate); + @Field(() => DateTimeISOResolver, { nullable: true }) + endDate?: Date | undefined | null; + get endDateDateTime(): DateTime | null { + return dateTimeFromSomething(this.endDate) ?? null; } static init({ @@ -35,8 +35,8 @@ export class MarathonNode extends TimestampedResource implements Node { }: { id: string; year: string; - startDate: Date; - endDate: Date; + startDate?: Date | null; + endDate?: Date | null; createdAt?: Date | null; updatedAt?: Date | null; }): MarathonNode { diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index e4fe02ca..5b3274a5 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -1,8 +1,19 @@ import { Prisma, PrismaClient } from "@prisma/client"; -import { CommitteeIdentifier, SortDirection } from "@ukdanceblue/common"; +import { + CommitteeIdentifier, + CommitteeRole, + DetailedError, + ErrorCode, + SortDirection, +} from "@ukdanceblue/common"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { + MarathonRepository, + UniqueMarathonParam, +} from "../marathon/MarathonRepository.js"; +import type { MembershipRepository } from "../membership/MembershipRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import * as CommitteeDescriptions from "./committeeDescriptions.js"; @@ -37,7 +48,11 @@ type CommitteeUniqueParam = @Service() export class CommitteeRepository { - constructor(private prisma: PrismaClient) {} + constructor( + private readonly prisma: PrismaClient, + private readonly membershipRepository: MembershipRepository, + private readonly marathonRepository: MarathonRepository + ) {} // Finders @@ -62,6 +77,49 @@ export class CommitteeRepository { return this.prisma.committee.findUnique({ where: param }); } + async assignPersonToCommittee( + personParam: SimpleUniqueParam, + committeeParam: CommitteeIdentifier, + committeeRole: CommitteeRole, + marathonParam?: UniqueMarathonParam + ) { + const person = await this.prisma.person.findUnique({ where: personParam }); + if (!person) { + throw new DetailedError(ErrorCode.NotFound, "Person not found"); + } + + if (!marathonParam) { + const nextMarathon = await this.marathonRepository.findNextMarathon(); + if (!nextMarathon) { + throw new DetailedError( + ErrorCode.NotFound, + "No upcoming marathon found and no marathon provided" + ); + } + marathonParam = { id: nextMarathon.id }; + } else { + // Check if the marathon exists + const val = + await this.marathonRepository.findMarathonByUnique(marathonParam); + if (!val) { + throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); + } + } + + const committee = await this.getCommittee(committeeParam, { + forMarathon: marathonParam, + }); + + for (const team of committee.correspondingTeams) { + // eslint-disable-next-line no-await-in-loop + await this.membershipRepository.assignPersonToTeam({ + personParam: { id: person.id }, + teamParam: { id: team.id }, + committeeRole, + }); + } + } + // Mutators deleteCommittee(uuid: string) { @@ -81,12 +139,23 @@ export class CommitteeRepository { // Committee getter - getCommittee(identifier: CommitteeIdentifier) { + getCommittee( + identifier: CommitteeIdentifier, + opts: { + forMarathon?: UniqueMarathonParam; + } = {} + ) { return this.prisma.committee.upsert({ ...CommitteeDescriptions[identifier], where: { identifier }, include: { - correspondingTeams: true, + correspondingTeams: opts.forMarathon + ? { + where: { + marathon: opts.forMarathon, + }, + } + : undefined, }, }); } diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index b59f954b..37558023 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -64,7 +64,7 @@ export class MarathonRepository { findCurrentMarathon() { return this.prisma.marathon.findFirst({ - orderBy: { year: "desc" }, + orderBy: { year: "asc" }, where: { startDate: { lte: new Date() }, endDate: { gte: new Date() } }, }); } diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index f2e4b478..4ac0af76 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,19 +1,10 @@ import { Prisma, PrismaClient } from "@prisma/client"; -import { - CommitteeRole, - MembershipPositionType, - SortDirection, -} from "@ukdanceblue/common"; +import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { SimpleUniqueParam } from "../shared.js"; -import { - buildMembershipOrder, - buildMembershipWhere, -} from "./membershipRepositoryUtils.js"; - const membershipBooleanKeys = [] as const; type MembershipBooleanKey = (typeof membershipBooleanKeys)[number]; @@ -54,62 +45,6 @@ export class MembershipRepository { return this.prisma.membership.findUnique({ where: param, include }); } - listMemberships({ - filters, - order, - skip, - take, - }: { - filters?: readonly MembershipFilters[] | undefined | null; - order?: readonly [key: string, sort: SortDirection][] | undefined | null; - skip?: number | undefined | null; - take?: number | undefined | null; - }) { - const where = buildMembershipWhere(filters); - const orderBy = buildMembershipOrder(order); - - return this.prisma.membership.findMany({ - where, - orderBy, - skip: skip ?? undefined, - take: take ?? undefined, - }); - } - - countMemberships({ - filters, - }: { - filters?: readonly MembershipFilters[] | undefined | null; - }) { - const where = buildMembershipWhere(filters); - - return this.prisma.membership.count({ - where, - }); - } - - createMembership(data: Prisma.MembershipCreateInput) { - return this.prisma.membership.create({ data }); - } - - updateMembership( - param: UniqueMembershipParam, - data: Prisma.MembershipUpdateInput - ) { - try { - return this.prisma.membership.update({ where: param, data }); - } catch (error) { - if ( - error instanceof Prisma.PrismaClientKnownRequestError && - error.code === "P2025" - ) { - return null; - } else { - throw error; - } - } - } - private async lookupPersonAndTeamId( personParam: SimpleUniqueParam, teamParam: SimpleUniqueParam @@ -234,19 +169,4 @@ export class MembershipRepository { }, }); } - - deleteMembership(param: UniqueMembershipParam) { - try { - return this.prisma.membership.delete({ where: param }); - } catch (error) { - if ( - error instanceof Prisma.PrismaClientKnownRequestError && - error.code === "P2025" - ) { - return null; - } else { - throw error; - } - } - } } diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index f956cef1..61c50f05 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -121,8 +121,6 @@ export const oidcCallback = async (ctx: Context) => { name: currentPerson.name, email: currentPerson.email, linkblue: currentPerson.linkblue, - committeeName: currentPerson.committeeName, - committeeRole: currentPerson.committeeRole, authIds: currentPerson.authIdPairs.map((a) => ({ source: a.source, value: a.value, diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index b90d4ff6..4cbc41da 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -2,6 +2,7 @@ import { CommitteeIdentifier, CommitteeRole } from "@ukdanceblue/common"; import { Container } from "typedi"; import { isDevelopment } from "./environment.js"; +import { CommitteeRepository } from "./repositories/committee/CommitteeRepository.js"; import { ConfigurationRepository } from "./repositories/configuration/ConfigurationRepository.js"; import { PersonRepository } from "./repositories/person/PersonRepository.js"; @@ -13,11 +14,10 @@ const { prisma } = await import("./prisma.js"); try { const personRepository = Container.get(PersonRepository); + const committeeRepository = Container.get(CommitteeRepository); const techCommittee: [string, string][] = [ ["jtho264@uky.edu", "jtho264"], - ["jp.huse@uky.edu", "jphu235"], - ["bartholomai@uky.edu", "mdba238"], ["Camille.Dyer@uky.edu", "chdy223"], ["str249@uky.edu", "str249"], ]; @@ -33,12 +33,22 @@ try { personRepository.createPerson({ email, linkblue, - committeeRole: CommitteeRole.Coordinator, - committeeName: CommitteeIdentifier.techCommittee, }) ) ); + await Promise.all( + techPeople.flatMap((person) => + committeeRepository.assignPersonToCommittee( + { + id: person.id, + }, + CommitteeIdentifier.techCommittee, + CommitteeRole.Coordinator + ) + ) + ); + const randomPeople = await Promise.all( randoms.map(([email, linkblue, name]) => personRepository.createPerson({ From 589331359160cbcaf5222a00f9a7d5cd1056a737 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 15 May 2024 00:58:27 +0000 Subject: [PATCH 042/153] Update personModelToResource to use personRepository for retrieving dbRole --- .../repositories/person/PersonRepository.ts | 68 +++++++++++++------ .../person/personModelToResource.ts | 23 ++++--- .../person/personRepositoryUtils.ts | 11 --- .../server/src/resolvers/DeviceResolver.ts | 10 ++- .../src/resolvers/MembershipResolver.ts | 8 ++- .../server/src/resolvers/PersonResolver.ts | 22 +++--- .../src/resolvers/PointEntryResolver.ts | 8 ++- packages/server/src/resolvers/context.ts | 5 +- .../src/routes/api/auth/oidcCallback.ts | 2 +- 9 files changed, 99 insertions(+), 58 deletions(-) diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index b1cbf7ac..e7613907 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -14,6 +14,7 @@ import { Service } from "typedi"; import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { SimpleUniqueParam } from "../shared.js"; import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; @@ -45,6 +46,20 @@ export type PersonOrderKeys = | "createdAt" | "updatedAt"; +export type UniquePersonParam = + | { + uuid: string; + } + | { + id: number; + } + | { + email: string; + } + | { + linkblue: string; + }; + @Service() export class PersonRepository { constructor(private prisma: PrismaClient) {} @@ -87,23 +102,11 @@ export class PersonRepository { return this.prisma.person.findUnique({ where: { linkblue } }); } - async findPersonByUnique( - param: - | { uuid: string } - | { id: number } - | { email: string } - | { linkblue: string } - ) { + async findPersonByUnique(param: UniquePersonParam) { return this.prisma.person.findUnique({ where: param }); } - async findPersonAndTeamsByUnique( - param: - | { uuid: string } - | { id: number } - | { email: string } - | { linkblue: string } - ) { + async findPersonAndTeamsByUnique(param: UniquePersonParam) { return this.prisma.person.findUnique({ where: param, include: { @@ -116,6 +119,31 @@ export class PersonRepository { }); } + async getDbRoleOfPerson(param: UniquePersonParam) { + const person = await this.prisma.person.findUnique({ + where: param, + select: { + linkblue: true, + memberships: { + select: { + committeeRole: true, + }, + }, + }, + }); + + if (!person) { + return null; + } + if (person.memberships.some((m) => m.committeeRole != null)) { + return DbRole.Committee; + } + if (person.linkblue) { + return DbRole.UKY; + } + return DbRole.Public; + } + listPeople({ filters, order, @@ -175,7 +203,7 @@ export class PersonRepository { } async findMembershipsOfPerson( - param: { uuid: string } | { id: number }, + param: UniquePersonParam, opts: | { position: MembershipPositionType; @@ -233,7 +261,7 @@ export class PersonRepository { } async updatePerson( - param: { uuid: string } | { id: number }, + param: UniquePersonParam, { name, email, @@ -249,8 +277,8 @@ export class PersonRepository { | { source: Exclude; value: string }[] | undefined | null; - memberOf?: ({ uuid: string } | { id: number })[] | undefined | null; - captainOf?: ({ uuid: string } | { id: number })[] | undefined | null; + memberOf?: SimpleUniqueParam[] | undefined | null; + captainOf?: SimpleUniqueParam[] | undefined | null; } ) { let personId: number; @@ -388,9 +416,7 @@ export class PersonRepository { } } - async deletePerson( - identifier: { uuid: string } | { id: number } - ): Promise { + async deletePerson(identifier: UniquePersonParam): Promise { try { return await this.prisma.person.delete({ where: identifier }); } catch (error) { diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index c5845263..d71974ae 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -1,23 +1,26 @@ import type { Person } from "@prisma/client"; import { DbRole, PersonNode } from "@ukdanceblue/common"; -export function personModelToResource(person: Person): PersonNode { - let dbRole: DbRole = DbRole.None; - if (person.committeeRole) { - dbRole = DbRole.Committee; - } else if (person.linkblue) { - dbRole = DbRole.UKY; - } else { - dbRole = DbRole.Public; - } +import type { PersonRepository } from "./PersonRepository.js"; + +export async function personModelToResource( + person: Person, + personRepository: PersonRepository +): Promise { + const dbRole = await personRepository.getDbRoleOfPerson({ + uuid: person.uuid, + }); return PersonNode.init({ uuid: person.uuid, name: person.name, email: person.email, linkblue: person.linkblue, - dbRole, createdAt: person.createdAt, updatedAt: person.updatedAt, + + // !!! Potential source of issues !!! + dbRole: dbRole ?? DbRole.None, + // !!! Potential source of issues !!! }); } diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index 6605484d..32aca3e7 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -3,7 +3,6 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, - oneOfFilterToPrisma, stringFilterToPrisma, } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; @@ -22,8 +21,6 @@ export function buildPersonOrder( case "name": case "email": case "linkblue": - case "committeeRole": - case "committeeName": case "createdAt": case "updatedAt": { orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; @@ -49,14 +46,6 @@ export function buildPersonWhere( where[filter.field] = stringFilterToPrisma(filter); break; } - case "committeeRole": { - where[filter.field] = oneOfFilterToPrisma(filter); - break; - } - case "committeeName": { - where[filter.field] = oneOfFilterToPrisma(filter); - break; - } case "createdAt": case "updatedAt": { where[filter.field] = dateFilterToPrisma(filter); diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 4bc0041d..ce4c4138 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -27,6 +27,7 @@ import { auditLogger } from "../lib/logging/auditLogging.js"; import { DeviceRepository } from "../repositories/device/DeviceRepository.js"; import { deviceModelToResource } from "../repositories/device/deviceModelToResource.js"; import { notificationDeliveryModelToResource } from "../repositories/notificationDelivery/notificationDeliveryModelToResource.js"; +import type { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { @@ -117,7 +118,10 @@ class NotificationDeliveriesArgs { @Resolver(() => DeviceNode) @Service() export class DeviceResolver { - constructor(private deviceRepository: DeviceRepository) {} + constructor( + private readonly deviceRepository: DeviceRepository, + private readonly personRepository: PersonRepository + ) {} @Query(() => GetDeviceByUuidResponse, { name: "device" }) async getByUuid(@Arg("uuid") uuid: string): Promise { @@ -190,7 +194,9 @@ export class DeviceResolver { ): Promise { const user = await this.deviceRepository.getLastLoggedInUser(device.id); - return user == null ? null : personModelToResource(user); + return user == null + ? null + : personModelToResource(user, this.personRepository); } @FieldResolver(() => [NotificationDeliveryNode]) diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 94098aa7..048fe58c 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -9,13 +9,17 @@ import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; +import type { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; @Resolver(() => MembershipNode) @Service() export class MembershipResolver { - constructor(private readonly membershipRepository: MembershipRepository) {} + constructor( + private readonly membershipRepository: MembershipRepository, + private readonly personRepository: PersonRepository + ) {} @FieldResolver(() => PersonNode) async person(@Root() membership: MembershipNode): Promise { @@ -30,7 +34,7 @@ export class MembershipResolver { throw new DetailedError(ErrorCode.NotFound, "$1Node not found"); } - return personModelToResource(row.person); + return personModelToResource(row.person, this.personRepository); } @FieldResolver(() => TeamNode) diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index a6a0c43f..3b492b57 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -152,7 +152,7 @@ export class PersonResolver { @Query(() => GetPersonResponse, { name: "person" }) async getByUuid(@Arg("uuid") uuid: string): Promise { - const row = await this.personRepository.findPersonByUuid(uuid); + const row = await this.personRepository.findPersonByUnique({ uuid }); if (row == null) { return GetPersonResponse.newOk( @@ -161,7 +161,7 @@ export class PersonResolver { } return GetPersonResponse.newOk( - personModelToResource(row) + await personModelToResource(row, this.personRepository) ); } @@ -170,7 +170,9 @@ export class PersonResolver { async getByLinkBlueId( @Arg("linkBlueId") linkBlueId: string ): Promise { - const row = await this.personRepository.findPersonByLinkblue(linkBlueId); + const row = await this.personRepository.findPersonByUnique({ + linkblue: linkBlueId, + }); if (row == null) { return GetPersonResponse.newOk( @@ -179,7 +181,7 @@ export class PersonResolver { } return GetPersonResponse.newOk( - personModelToResource(row) + await personModelToResource(row, this.personRepository) ); } @@ -206,7 +208,9 @@ export class PersonResolver { ]); return ListPeopleResponse.newPaginated({ - data: rows.map((row) => personModelToResource(row)), + data: await Promise.all( + rows.map((row) => personModelToResource(row, this.personRepository)) + ), total, page: args.page, pageSize: args.pageSize, @@ -226,7 +230,9 @@ export class PersonResolver { const rows = await this.personRepository.searchByName(name); return GetPeopleResponse.newOk( - rows.map((row) => personModelToResource(row)) + await Promise.all( + rows.map((row) => personModelToResource(row, this.personRepository)) + ) ); } @@ -242,7 +248,7 @@ export class PersonResolver { }); return CreatePersonResponse.newCreated( - personModelToResource(person), + await personModelToResource(person, this.personRepository), person.uuid ); } @@ -273,7 +279,7 @@ export class PersonResolver { } return GetPersonResponse.newOk( - personModelToResource(row) + await personModelToResource(row, this.personRepository) ); } diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 6ca71b42..f9ff6969 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -24,6 +24,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import type { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { PointEntryRepository } from "../repositories/pointEntry/PointEntryRepository.js"; import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; @@ -96,7 +97,10 @@ class ListPointEntriesArgs extends FilteredListQueryArgs< @Resolver(() => PointEntryNode) @Service() export class PointEntryResolver { - constructor(private readonly pointEntryRepository: PointEntryRepository) {} + constructor( + private readonly pointEntryRepository: PointEntryRepository, + private readonly personRepository: PersonRepository + ) {} @Query(() => GetPointEntryByUuidResponse, { name: "pointEntry" }) async getByUuid( @@ -178,7 +182,7 @@ export class PointEntryResolver { uuid: pointEntry.id, }); - return model ? personModelToResource(model) : null; + return model ? personModelToResource(model, this.personRepository) : null; } @FieldResolver(() => TeamNode) diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index a02b5c49..a845dbe8 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -54,7 +54,10 @@ export const graphqlContextFunction: ContextFunction< }); if (person) { - const personResource = personModelToResource(person); + const personResource = await personModelToResource( + person, + personRepository + ); logger.trace("graphqlContextFunction Found user", personResource); return { diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index 61c50f05..a00e6d60 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -134,7 +134,7 @@ export const oidcCallback = async (ctx: Context) => { const jwt = makeUserJwt( makeUserData( - personModelToResource(updatedPerson), + await personModelToResource(updatedPerson, personRepository), AuthSource.LinkBlue, currentPerson.memberships.map((m) => m.team.uuid), currentPerson.memberships From dada276181bac7ef3028ab95da9719be0cdb63df Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 7 May 2024 21:47:15 +0000 Subject: [PATCH 043/153] Add Skyler Trowel and Camille Dyer as App Coordinators for DB25 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0e8876b8..674360af 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,9 @@ Project Link: DB22, DB23, DB24 - [Jackson Huse](https://github.com/jphuse) - App Design Coordinator - DB23, DB24 +- [Skyler Trowel](https://github.com/smtrowel) - App Development Coordinator - + DB25 +- [Camille Dyer](https://github.com/cdyer8) - App Design Coordinator - DB25 - [Everyone on the DanceBlue committee](http://www.danceblue.org/meet-the-team)

(back to top)

From 5b8c0554a796f9077be79711e854b3804eaf6ec2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 15 May 2024 01:13:08 +0000 Subject: [PATCH 044/153] Start updating mobile for changed API --- codegen.ts | 5 ++--- .../src/common/components/ImageView/ImageView.tsx | 4 ++-- .../mobile/src/common/fragments/Configuration.ts | 6 +++--- .../src/common/fragments/NotificationScreenGQL.ts | 8 ++++---- packages/mobile/src/context/auth.tsx | 12 ++++-------- .../root/EventScreen/EventScreenFragment.ts | 9 ++++++--- .../root/ProfileScreen/ProfileScreen.tsx | 8 ++------ packages/mobile/src/navigation/root/RootScreen.tsx | 6 ++---- .../root/tab/EventListScreen/eventListUtils.ts | 9 +++++---- .../root/tab/ExplorerScreen/useExplorerFeed.tsx | 2 +- .../tab/MarathonScreen/HourScreenComponent.tsx | 4 ++-- .../spirit/ScoreBoardScreen/ScoreBoardScreen.tsx | 8 ++++---- .../src/navigation/root/tab/spirit/SpiritStack.tsx | 4 ++-- .../root/tab/spirit/TeamScreen/TeamScreen.tsx | 6 +++--- .../forms/notification/SingleNotificationGQL.ts | 4 ++-- .../src/elements/forms/person/PersonFormsGQL.ts | 4 ++-- .../elements/forms/person/edit/PersonEditorGQL.ts | 4 ++-- .../src/elements/forms/team/edit/TeamEditorGQL.ts | 4 ++-- .../portal/src/elements/tables/PeopleTable.tsx | 4 ++-- packages/portal/src/elements/tables/TeamsTable.tsx | 4 ++-- .../notification/NotificationDeliveriesTable.tsx | 4 ++-- .../tables/notification/NotificationsTable.tsx | 4 ++-- .../tables/point-entry/PointEntryTable.tsx | 4 ++-- .../src/elements/viewers/person/PersonViewer.tsx | 12 ++++-------- .../src/elements/viewers/team/TeamViewer.tsx | 14 ++++---------- packages/portal/src/pages/config/useConfig.ts | 4 ++-- .../src/pages/events/list-events/EventsTable.tsx | 9 ++++++--- .../single-event/edit-event/EventEditorGQL.ts | 9 ++++++--- .../events/single-event/view-event/EventViewer.tsx | 9 ++++++--- .../portal/src/pages/images/list/ImagesTable.tsx | 4 ++-- .../src/pages/marathon/overview/MarathonsTable.tsx | 4 ++-- .../pages/marathon/single/view/MarathonViewer.tsx | 6 +++--- schema.graphql | 5 +++-- 33 files changed, 98 insertions(+), 105 deletions(-) diff --git a/codegen.ts b/codegen.ts index 91dfcbec..8ec74a6b 100644 --- a/codegen.ts +++ b/codegen.ts @@ -34,8 +34,8 @@ const config: TypeScriptPluginConfig = { AuthSource: "../index.js#AuthSource", // AccessLevel: "../index.js#AccessLevel", DbRole: "../index.js#DbRole", - CommitteeRole: "../index.js#CommitteeRole", - CommitteeIdentifier: "../index.js#CommitteeIdentifier", + // CommitteeRole: "../index.js#CommitteeRole", + // CommitteeIdentifier: "../index.js#CommitteeIdentifier", // ErrorCode: "../index.js#ErrorCode", MembershipPositionType: "../index.js#MembershipPositionType", TeamLegacyStatus: "../index.js#TeamLegacyStatus", @@ -48,7 +48,6 @@ const config: TypeScriptPluginConfig = { }, scalars: { LuxonDateRange: "string", - LuxonDateTime: "string", LuxonDuration: "string", ...graphqlScalarsClientDefs, }, diff --git a/packages/mobile/src/common/components/ImageView/ImageView.tsx b/packages/mobile/src/common/components/ImageView/ImageView.tsx index d7a5632e..de83f3ec 100644 --- a/packages/mobile/src/common/components/ImageView/ImageView.tsx +++ b/packages/mobile/src/common/components/ImageView/ImageView.tsx @@ -6,8 +6,8 @@ import { import { Image, type ImageProps } from "expo-image"; export const ImageViewFragment = graphql(/* GraphQL */ ` - fragment ImageViewFragment on ImageResource { - uuid + fragment ImageViewFragment on ImageNode { + id url thumbHash alt diff --git a/packages/mobile/src/common/fragments/Configuration.ts b/packages/mobile/src/common/fragments/Configuration.ts index a98a1ecc..3db382d7 100644 --- a/packages/mobile/src/common/fragments/Configuration.ts +++ b/packages/mobile/src/common/fragments/Configuration.ts @@ -1,15 +1,15 @@ import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; export const SimpleConfigFragment = graphql(/* GraphQL */ ` - fragment SimpleConfig on ConfigurationResource { - uuid + fragment SimpleConfig on ConfigurationNode { + id key value } `); export const FullConfigFragment = graphql(/* GraphQL */ ` - fragment FullConfig on ConfigurationResource { + fragment FullConfig on ConfigurationNode { ...SimpleConfig validAfter validUntil diff --git a/packages/mobile/src/common/fragments/NotificationScreenGQL.ts b/packages/mobile/src/common/fragments/NotificationScreenGQL.ts index 4c9e160b..a6597f0d 100644 --- a/packages/mobile/src/common/fragments/NotificationScreenGQL.ts +++ b/packages/mobile/src/common/fragments/NotificationScreenGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; export const NotificationFragment = graphql(/* GraphQL */ ` - fragment NotificationFragment on NotificationResource { - uuid + fragment NotificationFragment on NotificationNode { + id title body url @@ -10,8 +10,8 @@ export const NotificationFragment = graphql(/* GraphQL */ ` `); export const NotificationDeliveryFragment = graphql(/* GraphQL */ ` - fragment NotificationDeliveryFragment on NotificationDeliveryResource { - uuid + fragment NotificationDeliveryFragment on NotificationDeliveryNode { + id sentAt notification { ...NotificationFragment diff --git a/packages/mobile/src/context/auth.tsx b/packages/mobile/src/context/auth.tsx index e6772f12..1df5d4b8 100644 --- a/packages/mobile/src/context/auth.tsx +++ b/packages/mobile/src/context/auth.tsx @@ -27,15 +27,11 @@ const authStateDocument = graphql(/* GraphQL */ ` query AuthState { me { data { - uuid + id } } loginState { - role { - dbRole - committeeIdentifier - committeeRole - } + dbRole loggedIn authSource } @@ -59,8 +55,8 @@ export function AuthStateProvider({ children }: { children: ReactNode }) { context: { loggedIn: data?.loginState.loggedIn, authSource: data?.loginState.authSource, - role: data?.loginState.role, - userUuid: data?.me.data?.uuid, + role: data?.loginState.dbRole, + userUuid: data?.me.data?.id, }, tags: ["graphql"], }); diff --git a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts index e11011b9..65c1a1e9 100644 --- a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts +++ b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts @@ -1,15 +1,18 @@ import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; export const EventScreenFragment = graphql(/* GraphQL */ ` - fragment EventScreenFragment on EventResource { - uuid + fragment EventScreenFragment on EventNode { + id title summary description location occurrences { uuid - interval + interval { + start + end + } fullDay } images { diff --git a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx index 8aa7f5a5..45d86cab 100644 --- a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx +++ b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx @@ -31,17 +31,13 @@ import { ProfileFooter } from "./ProfileFooter"; export const ProfileScreenAuthFragment = graphql(/* GraphQL */ ` fragment ProfileScreenAuthFragment on LoginState { - role { - committeeIdentifier - committeeRole - dbRole - } + dbRole authSource } `); export const ProfileScreenUserFragment = graphql(/* GraphQL */ ` - fragment ProfileScreenUserFragment on PersonResource { + fragment ProfileScreenUserFragment on PersonNode { name linkblue teams { diff --git a/packages/mobile/src/navigation/root/RootScreen.tsx b/packages/mobile/src/navigation/root/RootScreen.tsx index ec36e329..97242777 100644 --- a/packages/mobile/src/navigation/root/RootScreen.tsx +++ b/packages/mobile/src/navigation/root/RootScreen.tsx @@ -41,9 +41,7 @@ const rootScreenDocument = graphql(/* GraphQL */ ` const RootScreenAuthFragment = graphql(/* GraphQL */ ` fragment RootScreenAuthFragment on LoginState { - role { - dbRole - } + dbRole } `); @@ -72,7 +70,7 @@ const RootScreen = () => { rootScreenData?.loginState ?? null ); const isLoggedIn = useMemo(() => { - return authData?.role.dbRole !== DbRole.None; + return authData?.dbRole !== DbRole.None; }, [authData]); const { colors } = useTheme(); diff --git a/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts b/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts index e6aee51a..3e9df05b 100644 --- a/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts +++ b/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts @@ -246,8 +246,8 @@ export const useEvents = ({ const [eventsQueryResult, refresh] = useQuery({ query: graphql(/* GraphQL */ ` query Events( - $earliestTimestamp: LuxonDateTime! - $lastTimestamp: LuxonDateTime! + $earliestTimestamp: DateTimeISO! + $lastTimestamp: DateTimeISO! ) { events( dateFilters: [ @@ -282,8 +282,9 @@ export const useEvents = ({ if (lastFetchKey.current !== eventsQueryResult.operation?.key) { if (!eventsQueryResult.fetching && eventsQueryResult.error == null) { Logger.debug( - `successfully fetched ${eventsQueryResult.data?.events.data - .length} events for ${month.toFormat("yyyy-LL")} from ${ + `successfully fetched ${ + eventsQueryResult.data?.events.data.length + } events for ${month.toFormat("yyyy-LL")} from ${ eventsQueryResult.operation?.context.meta?.cacheOutcome === "hit" ? "cache" : "network" diff --git a/packages/mobile/src/navigation/root/tab/ExplorerScreen/useExplorerFeed.tsx b/packages/mobile/src/navigation/root/tab/ExplorerScreen/useExplorerFeed.tsx index 6591d127..68cbd75a 100644 --- a/packages/mobile/src/navigation/root/tab/ExplorerScreen/useExplorerFeed.tsx +++ b/packages/mobile/src/navigation/root/tab/ExplorerScreen/useExplorerFeed.tsx @@ -12,7 +12,7 @@ import { useQuery } from "urql"; const serverFeedDocument = graphql(/* GraphQL */ ` query ServerFeed { feed(limit: 20) { - uuid + id title createdAt textContent diff --git a/packages/mobile/src/navigation/root/tab/MarathonScreen/HourScreenComponent.tsx b/packages/mobile/src/navigation/root/tab/MarathonScreen/HourScreenComponent.tsx index 5e6f0fdd..d1a37d8d 100644 --- a/packages/mobile/src/navigation/root/tab/MarathonScreen/HourScreenComponent.tsx +++ b/packages/mobile/src/navigation/root/tab/MarathonScreen/HourScreenComponent.tsx @@ -17,8 +17,8 @@ import { } from "react-native"; const HourScreenFragment = graphql(/* GraphQL */ ` - fragment HourScreenFragment on MarathonHourResource { - uuid + fragment HourScreenFragment on MarathonHourNode { + id title details durationInfo diff --git a/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx b/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx index 21f642b6..24d14906 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx @@ -32,8 +32,8 @@ function addOrdinal(num: number) { } const ScoreBoardFragment = graphql(/* GraphQL */ ` - fragment ScoreBoardFragment on TeamResource { - uuid + fragment ScoreBoardFragment on TeamNode { + id name totalPoints legacyStatus @@ -42,8 +42,8 @@ const ScoreBoardFragment = graphql(/* GraphQL */ ` `); const HighlightedTeamFragment = graphql(/* GraphQL */ ` - fragment HighlightedTeamFragment on TeamResource { - uuid + fragment HighlightedTeamFragment on TeamNode { + id name legacyStatus type diff --git a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx index aad9ed13..03d7b780 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx @@ -15,7 +15,7 @@ const scoreBoardDocument = graphql(/* GraphQL */ ` query ScoreBoardDocument($type: [TeamType!]) { me { data { - uuid + id teams { team { ...HighlightedTeamFragment @@ -40,7 +40,7 @@ const scoreBoardDocument = graphql(/* GraphQL */ ` const currentMarathonDocument = graphql(/* GraphQL */ ` query ActiveMarathonDocument { currentMarathon { - uuid + id } } `); diff --git a/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx b/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx index c3f23159..a05b46b8 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx @@ -13,13 +13,13 @@ import { useWindowDimensions } from "react-native"; import TeamInformation from "./TeamInformation"; export const MyTeamFragment = graphql(/* GraphQL */ ` - fragment MyTeamFragment on TeamResource { - uuid + fragment MyTeamFragment on TeamNode { + id name totalPoints pointEntries { personFrom { - uuid + id name linkblue } diff --git a/packages/portal/src/elements/forms/notification/SingleNotificationGQL.ts b/packages/portal/src/elements/forms/notification/SingleNotificationGQL.ts index 4d4e0d9c..7ee6a5a5 100644 --- a/packages/portal/src/elements/forms/notification/SingleNotificationGQL.ts +++ b/packages/portal/src/elements/forms/notification/SingleNotificationGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const SingleNotificationFragment = graphql(/* GraphQL */ ` - fragment SingleNotificationFragment on NotificationResource { - uuid + fragment SingleNotificationFragment on NotificationNode { + id title body deliveryIssue diff --git a/packages/portal/src/elements/forms/person/PersonFormsGQL.ts b/packages/portal/src/elements/forms/person/PersonFormsGQL.ts index 2fb3e765..2d6a90ae 100644 --- a/packages/portal/src/elements/forms/person/PersonFormsGQL.ts +++ b/packages/portal/src/elements/forms/person/PersonFormsGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const TeamNameFragment = graphql(/* GraphQL */ ` - fragment TeamNameFragment on TeamResource { - uuid + fragment TeamNameFragment on TeamNode { + id name } `); diff --git a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts index 73f0906a..3488fa4d 100644 --- a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts +++ b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const PersonEditorFragment = graphql(/* GraphQL */ ` - fragment PersonEditorFragment on PersonResource { - uuid + fragment PersonEditorFragment on PersonNode { + id name linkblue email diff --git a/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts b/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts index 5e8cbf3f..d35e4ffb 100644 --- a/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts +++ b/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const TeamEditorFragment = graphql(/* GraphQL */ ` - fragment TeamEditorFragment on TeamResource { - uuid + fragment TeamEditorFragment on TeamNode { + id name marathonYear legacyStatus diff --git a/packages/portal/src/elements/tables/PeopleTable.tsx b/packages/portal/src/elements/tables/PeopleTable.tsx index 03914478..ffe060ad 100644 --- a/packages/portal/src/elements/tables/PeopleTable.tsx +++ b/packages/portal/src/elements/tables/PeopleTable.tsx @@ -19,8 +19,8 @@ import { Button, Flex, Table } from "antd"; import { useQuery } from "urql"; const PeopleTableFragment = graphql(/* GraphQL */ ` - fragment PeopleTableFragment on PersonResource { - uuid + fragment PeopleTableFragment on PersonNode { + id name linkblue email diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index 8832bf6c..a6f4b4f9 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -41,8 +41,8 @@ const teamsTableQueryDocument = graphql(/* GraphQL */ ` `); export const TeamsTableFragment = graphql(/* GraphQL */ ` - fragment TeamsTableFragment on TeamResource { - uuid + fragment TeamsTableFragment on TeamNode { + id type name legacyStatus diff --git a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx index d669dc8c..72188e31 100644 --- a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx @@ -11,8 +11,8 @@ import { DateTime } from "luxon"; import { useQuery } from "urql"; const NotificationDeliveriesTableFragment = graphql(/* GraphQL */ ` - fragment NotificationDeliveriesTableFragment on NotificationDeliveryResource { - uuid + fragment NotificationDeliveriesTableFragment on NotificationDeliveryNode { + id deliveryError receiptCheckedAt sentAt diff --git a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx index 64dd6814..081c412d 100644 --- a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx @@ -13,8 +13,8 @@ import { DateTime } from "luxon"; import { useQuery } from "urql"; const NotificationsTableFragment = graphql(/* GraphQL */ ` - fragment NotificationsTableFragment on NotificationResource { - uuid + fragment NotificationsTableFragment on NotificationNode { + id title body deliveryIssue diff --git a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx index c5ed210f..a820b93c 100644 --- a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx +++ b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx @@ -11,8 +11,8 @@ import type { UseQueryExecute } from "urql"; import { usePointEntryDeletePopup } from "./PointEntryDeletePopup"; export const PointEntryTableFragment = graphql(/* GraphQL */ ` - fragment PointEntryTableFragment on PointEntryResource { - uuid + fragment PointEntryTableFragment on PointEntryNode { + id personFrom { name linkblue diff --git a/packages/portal/src/elements/viewers/person/PersonViewer.tsx b/packages/portal/src/elements/viewers/person/PersonViewer.tsx index 53cf5f28..5fc2981f 100644 --- a/packages/portal/src/elements/viewers/person/PersonViewer.tsx +++ b/packages/portal/src/elements/viewers/person/PersonViewer.tsx @@ -11,20 +11,16 @@ import { Button, Descriptions, Empty, Flex, Typography } from "antd"; import { usePersonDeletePopup } from "./PersonDeletePopup"; export const PersonViewerFragment = graphql(/* GraphQL */ ` - fragment PersonViewerFragment on PersonResource { - uuid + fragment PersonViewerFragment on PersonNode { + id name linkblue email - role { - dbRole - committeeRole - committeeIdentifier - } + dbRole teams { position team { - uuid + id name } } diff --git a/packages/portal/src/elements/viewers/team/TeamViewer.tsx b/packages/portal/src/elements/viewers/team/TeamViewer.tsx index d18d1af7..e8c367ba 100644 --- a/packages/portal/src/elements/viewers/team/TeamViewer.tsx +++ b/packages/portal/src/elements/viewers/team/TeamViewer.tsx @@ -10,8 +10,8 @@ import { Button, Descriptions, Empty, Flex } from "antd"; import { useTeamDeletePopup } from "./TeamDeletePopup"; export const TeamViewerFragment = graphql(/* GraphQL */ ` - fragment TeamViewerFragment on TeamResource { - uuid + fragment TeamViewerFragment on TeamNode { + id name marathonYear legacyStatus @@ -19,17 +19,11 @@ export const TeamViewerFragment = graphql(/* GraphQL */ ` type members { person { - uuid - name - linkblue - } - } - captains { - person { - uuid + id name linkblue } + position } } `); diff --git a/packages/portal/src/pages/config/useConfig.ts b/packages/portal/src/pages/config/useConfig.ts index bdbaf524..0a45ba85 100644 --- a/packages/portal/src/pages/config/useConfig.ts +++ b/packages/portal/src/pages/config/useConfig.ts @@ -8,8 +8,8 @@ import { useMemo } from "react"; import { useQuery } from "urql"; export const ConfigFragment = graphql(/* GraphQL */ ` - fragment ConfigFragment on ConfigurationResource { - uuid + fragment ConfigFragment on ConfigurationNode { + id key value validAfter diff --git a/packages/portal/src/pages/events/list-events/EventsTable.tsx b/packages/portal/src/pages/events/list-events/EventsTable.tsx index 10bb6638..39d6ca97 100644 --- a/packages/portal/src/pages/events/list-events/EventsTable.tsx +++ b/packages/portal/src/pages/events/list-events/EventsTable.tsx @@ -16,13 +16,16 @@ import { useCallback, useMemo } from "react"; import { useQuery } from "urql"; const EventsTableFragment = graphql(/* GraphQL */ ` - fragment EventsTableFragment on EventResource { - uuid + fragment EventsTableFragment on EventNode { + id title description occurrences { uuid - interval + interval { + start + end + } fullDay } summary diff --git a/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts b/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts index 10b1f120..fc98ce9a 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts +++ b/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts @@ -1,15 +1,18 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const EventEditorFragment = graphql(/* GraphQL */ ` - fragment EventEditorFragment on EventResource { - uuid + fragment EventEditorFragment on EventNode { + id title summary description location occurrences { uuid - interval + interval { + start + end + } fullDay } images { diff --git a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx index afba7e3f..5b090201 100644 --- a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx +++ b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx @@ -15,14 +15,17 @@ import { thumbHashToDataURL } from "thumbhash"; import { useEventDeletePopup } from "./EventDeletePopup"; export const EventViewerFragment = graphql(/* GraphQL */ ` - fragment EventViewerFragment on EventResource { - uuid + fragment EventViewerFragment on EventNode { + id title summary description location occurrences { - interval + interval { + start + end + } fullDay } images { diff --git a/packages/portal/src/pages/images/list/ImagesTable.tsx b/packages/portal/src/pages/images/list/ImagesTable.tsx index 16e0fc5c..5a795c8d 100644 --- a/packages/portal/src/pages/images/list/ImagesTable.tsx +++ b/packages/portal/src/pages/images/list/ImagesTable.tsx @@ -14,8 +14,8 @@ import { thumbHashToDataURL } from "thumbhash"; import { useQuery } from "urql"; const ImagesTableFragment = graphql(/* GraphQL */ ` - fragment ImagesTableFragment on ImageResource { - uuid + fragment ImagesTableFragment on ImageNode { + id url thumbHash height diff --git a/packages/portal/src/pages/marathon/overview/MarathonsTable.tsx b/packages/portal/src/pages/marathon/overview/MarathonsTable.tsx index b1a7729a..80d3ccd2 100644 --- a/packages/portal/src/pages/marathon/overview/MarathonsTable.tsx +++ b/packages/portal/src/pages/marathon/overview/MarathonsTable.tsx @@ -4,8 +4,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { Button, Empty, Table } from "antd"; export const MarathonTableFragment = graphql(/* GraphQL */ ` - fragment MarathonTableFragment on MarathonResource { - uuid + fragment MarathonTableFragment on MarathonNode { + id year startDate endDate diff --git a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx index c76fd155..c606fe30 100644 --- a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx +++ b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx @@ -10,13 +10,13 @@ import { DateTime } from "luxon"; import { useMemo } from "react"; export const MarathonViewerFragment = graphql(/* GraphQL */ ` - fragment MarathonViewerFragment on MarathonResource { - uuid + fragment MarathonViewerFragment on MarathonNode { + id year startDate endDate hours { - uuid + id shownStartingAt title } diff --git a/schema.graphql b/schema.graphql index 99c18990..52c56894 100644 --- a/schema.graphql +++ b/schema.graphql @@ -740,10 +740,10 @@ type MarathonHourNode implements Node { type MarathonNode implements Node { createdAt: DateTimeISO - endDate: DateTimeISO! + endDate: DateTimeISO hours: [MarathonHourNode!]! id: ID! - startDate: DateTimeISO! + startDate: DateTimeISO updatedAt: DateTimeISO year: String! } @@ -1048,6 +1048,7 @@ enum NumericComparator { type PersonNode implements Node { captaincies: [MembershipNode!]! @deprecated(reason: "Use teams instead and filter by position") + committees: [MembershipNode!]! createdAt: DateTimeISO dbRole: DbRole! email: String! From 4627ff449c9fece494bde29e641d0f642ff156e6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 15 May 2024 01:39:57 +0000 Subject: [PATCH 045/153] More fixes on mobile for new API --- .../common/lib/graphql-client-public/gql.ts | 72 +-- .../lib/graphql-client-public/graphql.ts | 606 +++++++++--------- .../common/lib/utility/time/intervalTools.ts | 82 ++- .../src/common/hooks/useMarathonTime.ts | 31 +- packages/mobile/src/context/auth.tsx | 9 +- .../root/EventScreen/EventScreen.tsx | 6 +- .../root/EventScreen/addToCalendar.ts | 6 +- .../NotificationScreen/NotificationScreen.tsx | 4 +- .../root/ProfileScreen/ProfileScreen.tsx | 2 +- .../EventListScreen/EventListRenderItem.tsx | 9 +- .../tab/EventListScreen/eventListUtils.ts | 8 +- .../tab/ExplorerScreen/useExplorerFeed.tsx | 4 +- .../MarathonScreen/HourScreenComponent.tsx | 2 +- .../MarathonCountdownScreen.tsx | 36 +- .../tab/MarathonScreen/MarathonScreen.tsx | 22 +- .../ScoreBoardScreen/ScoreBoardScreen.tsx | 10 +- .../root/tab/spirit/SpiritStack.tsx | 2 +- .../root/tab/spirit/TeamScreen/TeamScreen.tsx | 2 +- 18 files changed, 498 insertions(+), 415 deletions(-) diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index 2c68b131..19f2d404 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -13,32 +13,32 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n fragment ImageViewFragment on ImageResource {\n uuid\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n": types.ImageViewFragmentFragmentDoc, - "\n fragment SimpleConfig on ConfigurationResource {\n uuid\n key\n value\n }\n": types.SimpleConfigFragmentDoc, - "\n fragment FullConfig on ConfigurationResource {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n": types.FullConfigFragmentDoc, - "\n fragment NotificationFragment on NotificationResource {\n uuid\n title\n body\n url\n }\n": types.NotificationFragmentFragmentDoc, - "\n fragment NotificationDeliveryFragment on NotificationDeliveryResource {\n uuid\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n": types.NotificationDeliveryFragmentFragmentDoc, + "\n fragment ImageViewFragment on ImageNode {\n id\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n": types.ImageViewFragmentFragmentDoc, + "\n fragment SimpleConfig on ConfigurationNode {\n id\n key\n value\n }\n": types.SimpleConfigFragmentDoc, + "\n fragment FullConfig on ConfigurationNode {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n": types.FullConfigFragmentDoc, + "\n fragment NotificationFragment on NotificationNode {\n id\n title\n body\n url\n }\n": types.NotificationFragmentFragmentDoc, + "\n fragment NotificationDeliveryFragment on NotificationDeliveryNode {\n id\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n": types.NotificationDeliveryFragmentFragmentDoc, "\n query useAllowedLoginTypes {\n activeConfiguration(key: \"ALLOWED_LOGIN_TYPES\") {\n data {\n ...SimpleConfig\n }\n }\n }\n": types.UseAllowedLoginTypesDocument, "\n query MarathonTime {\n nextMarathon {\n startDate\n endDate\n }\n }\n": types.MarathonTimeDocument, "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n data {\n linkblue\n }\n }\n }\n": types.UseTabBarConfigDocument, "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n ": types.TriviaCrackDocument, - "\n query AuthState {\n me {\n data {\n uuid\n }\n }\n loginState {\n role {\n dbRole\n committeeIdentifier\n committeeRole\n }\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, + "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, "\n mutation SetDevice($input: RegisterDeviceInput!) {\n registerDevice(input: $input) {\n ok\n }\n }\n": types.SetDeviceDocument, - "\n fragment EventScreenFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, + "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, "\n query DeviceNotifications(\n $deviceUuid: String!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n": types.DeviceNotificationsDocument, - "\n fragment ProfileScreenAuthFragment on LoginState {\n role {\n committeeIdentifier\n committeeRole\n dbRole\n }\n authSource\n }\n": types.ProfileScreenAuthFragmentFragmentDoc, - "\n fragment ProfileScreenUserFragment on PersonResource {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, + "\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n": types.ProfileScreenAuthFragmentFragmentDoc, + "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n": types.RootScreenDocumentDocument, - "\n fragment RootScreenAuthFragment on LoginState {\n role {\n dbRole\n }\n }\n": types.RootScreenAuthFragmentFragmentDoc, - "\n query Events(\n $earliestTimestamp: LuxonDateTime!\n $lastTimestamp: LuxonDateTime!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, - "\n query ServerFeed {\n feed(limit: 20) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n": types.ServerFeedDocument, - "\n fragment HourScreenFragment on MarathonHourResource {\n uuid\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n": types.HourScreenFragmentFragmentDoc, + "\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n": types.RootScreenAuthFragmentFragmentDoc, + "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, + "\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n": types.ServerFeedDocument, + "\n fragment HourScreenFragment on MarathonHourNode {\n id\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n": types.HourScreenFragmentFragmentDoc, "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n nextMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n": types.MarathonScreenDocument, - "\n fragment ScoreBoardFragment on TeamResource {\n uuid\n name\n totalPoints\n legacyStatus\n type\n }\n": types.ScoreBoardFragmentFragmentDoc, - "\n fragment HighlightedTeamFragment on TeamResource {\n uuid\n name\n legacyStatus\n type\n }\n": types.HighlightedTeamFragmentFragmentDoc, - "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n uuid\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, - "\n query ActiveMarathonDocument {\n currentMarathon {\n uuid\n }\n }\n": types.ActiveMarathonDocumentDocument, - "\n fragment MyTeamFragment on TeamResource {\n uuid\n name\n totalPoints\n pointEntries {\n personFrom {\n uuid\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n": types.MyTeamFragmentFragmentDoc, + "\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n": types.ScoreBoardFragmentFragmentDoc, + "\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n": types.HighlightedTeamFragmentFragmentDoc, + "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, + "\n query ActiveMarathonDocument {\n currentMarathon {\n id\n }\n }\n": types.ActiveMarathonDocumentDocument, + "\n fragment MyTeamFragment on TeamNode {\n id\n name\n totalPoints\n pointEntries {\n personFrom {\n id\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n": types.MyTeamFragmentFragmentDoc, }; /** @@ -58,23 +58,23 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ImageViewFragment on ImageResource {\n uuid\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n"): (typeof documents)["\n fragment ImageViewFragment on ImageResource {\n uuid\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n"]; +export function graphql(source: "\n fragment ImageViewFragment on ImageNode {\n id\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n"): (typeof documents)["\n fragment ImageViewFragment on ImageNode {\n id\n url\n thumbHash\n alt\n width\n height\n mimeType\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment SimpleConfig on ConfigurationResource {\n uuid\n key\n value\n }\n"): (typeof documents)["\n fragment SimpleConfig on ConfigurationResource {\n uuid\n key\n value\n }\n"]; +export function graphql(source: "\n fragment SimpleConfig on ConfigurationNode {\n id\n key\n value\n }\n"): (typeof documents)["\n fragment SimpleConfig on ConfigurationNode {\n id\n key\n value\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment FullConfig on ConfigurationResource {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n"): (typeof documents)["\n fragment FullConfig on ConfigurationResource {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n"]; +export function graphql(source: "\n fragment FullConfig on ConfigurationNode {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n"): (typeof documents)["\n fragment FullConfig on ConfigurationNode {\n ...SimpleConfig\n validAfter\n validUntil\n createdAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment NotificationFragment on NotificationResource {\n uuid\n title\n body\n url\n }\n"): (typeof documents)["\n fragment NotificationFragment on NotificationResource {\n uuid\n title\n body\n url\n }\n"]; +export function graphql(source: "\n fragment NotificationFragment on NotificationNode {\n id\n title\n body\n url\n }\n"): (typeof documents)["\n fragment NotificationFragment on NotificationNode {\n id\n title\n body\n url\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment NotificationDeliveryFragment on NotificationDeliveryResource {\n uuid\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n"): (typeof documents)["\n fragment NotificationDeliveryFragment on NotificationDeliveryResource {\n uuid\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n"]; +export function graphql(source: "\n fragment NotificationDeliveryFragment on NotificationDeliveryNode {\n id\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n"): (typeof documents)["\n fragment NotificationDeliveryFragment on NotificationDeliveryNode {\n id\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -94,7 +94,7 @@ export function graphql(source: "\n query TriviaCrack {\n activeConf /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query AuthState {\n me {\n data {\n uuid\n }\n }\n loginState {\n role {\n dbRole\n committeeIdentifier\n committeeRole\n }\n loggedIn\n authSource\n }\n }\n"): (typeof documents)["\n query AuthState {\n me {\n data {\n uuid\n }\n }\n loginState {\n role {\n dbRole\n committeeIdentifier\n committeeRole\n }\n loggedIn\n authSource\n }\n }\n"]; +export function graphql(source: "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"): (typeof documents)["\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -102,7 +102,7 @@ export function graphql(source: "\n mutation SetDevice($input: RegisterDeviceIn /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventScreenFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"): (typeof documents)["\n fragment EventScreenFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"]; +export function graphql(source: "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"): (typeof documents)["\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -110,11 +110,11 @@ export function graphql(source: "\n query DeviceNotifications(\n $deviceUuid /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ProfileScreenAuthFragment on LoginState {\n role {\n committeeIdentifier\n committeeRole\n dbRole\n }\n authSource\n }\n"): (typeof documents)["\n fragment ProfileScreenAuthFragment on LoginState {\n role {\n committeeIdentifier\n committeeRole\n dbRole\n }\n authSource\n }\n"]; +export function graphql(source: "\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n"): (typeof documents)["\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ProfileScreenUserFragment on PersonResource {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"): (typeof documents)["\n fragment ProfileScreenUserFragment on PersonResource {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"): (typeof documents)["\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -122,19 +122,19 @@ export function graphql(source: "\n query RootScreenDocument {\n loginState /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment RootScreenAuthFragment on LoginState {\n role {\n dbRole\n }\n }\n"): (typeof documents)["\n fragment RootScreenAuthFragment on LoginState {\n role {\n dbRole\n }\n }\n"]; +export function graphql(source: "\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n"): (typeof documents)["\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query Events(\n $earliestTimestamp: LuxonDateTime!\n $lastTimestamp: LuxonDateTime!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "): (typeof documents)["\n query Events(\n $earliestTimestamp: LuxonDateTime!\n $lastTimestamp: LuxonDateTime!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "]; +export function graphql(source: "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "): (typeof documents)["\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ServerFeed {\n feed(limit: 20) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n"): (typeof documents)["\n query ServerFeed {\n feed(limit: 20) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n"]; +export function graphql(source: "\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n"): (typeof documents)["\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment HourScreenFragment on MarathonHourResource {\n uuid\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n"): (typeof documents)["\n fragment HourScreenFragment on MarathonHourResource {\n uuid\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n"]; +export function graphql(source: "\n fragment HourScreenFragment on MarathonHourNode {\n id\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n"): (typeof documents)["\n fragment HourScreenFragment on MarathonHourNode {\n id\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -142,23 +142,23 @@ export function graphql(source: "\n query MarathonScreen {\n currentMarathon /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ScoreBoardFragment on TeamResource {\n uuid\n name\n totalPoints\n legacyStatus\n type\n }\n"): (typeof documents)["\n fragment ScoreBoardFragment on TeamResource {\n uuid\n name\n totalPoints\n legacyStatus\n type\n }\n"]; +export function graphql(source: "\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n"): (typeof documents)["\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment HighlightedTeamFragment on TeamResource {\n uuid\n name\n legacyStatus\n type\n }\n"): (typeof documents)["\n fragment HighlightedTeamFragment on TeamResource {\n uuid\n name\n legacyStatus\n type\n }\n"]; +export function graphql(source: "\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n"): (typeof documents)["\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n uuid\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n uuid\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ActiveMarathonDocument {\n currentMarathon {\n uuid\n }\n }\n"): (typeof documents)["\n query ActiveMarathonDocument {\n currentMarathon {\n uuid\n }\n }\n"]; +export function graphql(source: "\n query ActiveMarathonDocument {\n currentMarathon {\n id\n }\n }\n"): (typeof documents)["\n query ActiveMarathonDocument {\n currentMarathon {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment MyTeamFragment on TeamResource {\n uuid\n name\n totalPoints\n pointEntries {\n personFrom {\n uuid\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n"): (typeof documents)["\n fragment MyTeamFragment on TeamResource {\n uuid\n name\n totalPoints\n pointEntries {\n personFrom {\n uuid\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment MyTeamFragment on TeamNode {\n id\n name\n totalPoints\n pointEntries {\n personFrom {\n id\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n"): (typeof documents)["\n fragment MyTeamFragment on TeamNode {\n id\n name\n totalPoints\n pointEntries {\n personFrom {\n id\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 02f60264..3c78b165 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -1,8 +1,6 @@ /* eslint-disable */ import type { AuthSource } from '../index.js'; import type { DbRole } from '../index.js'; -import type { CommitteeRole } from '../index.js'; -import type { CommitteeIdentifier } from '../index.js'; import type { MembershipPositionType } from '../index.js'; import type { TeamLegacyStatus } from '../index.js'; import type { TeamType } from '../index.js'; @@ -28,10 +26,6 @@ export type Scalars = { DateTimeISO: { input: Date | string; output: Date | string; } /** A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. */ EmailAddress: { input: string; output: string; } - /** Date range custom scalar type (just an ISO 8601 interval) */ - LuxonDateRange: { input: string; output: string; } - /** Luxon DateTime custom scalar type */ - LuxonDateTime: { input: string; output: string; } /** Integers that will have a value of 0 or more. */ NonNegativeInt: { input: number; output: number; } /** Integers that will have a value greater than 0. */ @@ -83,43 +77,33 @@ export type AcknowledgeDeliveryIssueResponse = AbstractGraphQlOkResponse & Graph export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'AddEventImageResponse'; - readonly data: ImageResource; + readonly data: ImageNode; readonly ok: Scalars['Boolean']['output']; }; -export type AuthIdPairResource = { - readonly __typename?: 'AuthIdPairResource'; - readonly source: AuthSource; - readonly value: Scalars['String']['output']; -}; - export { AuthSource }; -export { CommitteeIdentifier }; - -export { CommitteeRole }; - -export type ConfigurationResource = { - readonly __typename?: 'ConfigurationResource'; +export type ConfigurationNode = Node & { + readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; readonly key: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly validAfter?: Maybe; - readonly validUntil?: Maybe; + readonly validAfter?: Maybe; + readonly validUntil?: Maybe; readonly value: Scalars['String']['output']; }; export type CreateConfigurationInput = { readonly key: Scalars['String']['input']; - readonly validAfter?: InputMaybe; - readonly validUntil?: InputMaybe; + readonly validAfter?: InputMaybe; + readonly validUntil?: InputMaybe; readonly value: Scalars['String']['input']; }; export type CreateConfigurationResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateConfigurationResponse'; - readonly data: ConfigurationResource; + readonly data: ConfigurationNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -134,12 +118,12 @@ export type CreateEventInput = { export type CreateEventOccurrenceInput = { readonly fullDay: Scalars['Boolean']['input']; - readonly interval: Scalars['LuxonDateRange']['input']; + readonly interval: IntervalIsoInput; }; export type CreateEventResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateEventResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -170,16 +154,16 @@ export type CreateMarathonInput = { export type CreatePersonInput = { readonly captainOf?: ReadonlyArray; + readonly dbRole?: InputMaybe; readonly email: Scalars['EmailAddress']['input']; readonly linkblue?: InputMaybe; readonly memberOf?: ReadonlyArray; readonly name?: InputMaybe; - readonly role?: InputMaybe; }; export type CreatePersonResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePersonResponse'; - readonly data: PersonResource; + readonly data: PersonNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -194,7 +178,7 @@ export type CreatePointEntryInput = { export type CreatePointEntryResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePointEntryResponse'; - readonly data: PointEntryResource; + readonly data: PointEntryNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -202,13 +186,13 @@ export type CreatePointEntryResponse = AbstractGraphQlCreatedResponse & Abstract export type CreatePointOpportunityInput = { readonly eventUuid?: InputMaybe; readonly name: Scalars['String']['input']; - readonly opportunityDate?: InputMaybe; + readonly opportunityDate?: InputMaybe; readonly type: TeamType; }; export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePointOpportunityResponse'; - readonly data: PointOpportunityResource; + readonly data: PointOpportunityNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -223,7 +207,7 @@ export type CreateTeamInput = { export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateTeamResponse'; - readonly data: TeamResource; + readonly data: TeamNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -276,6 +260,23 @@ export type DeleteTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse readonly ok: Scalars['Boolean']['output']; }; +export type DeviceNode = Node & { + readonly __typename?: 'DeviceNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly lastLoggedInUser?: Maybe; + readonly lastLogin?: Maybe; + readonly notificationDeliveries: ReadonlyArray; + readonly updatedAt?: Maybe; +}; + + +export type DeviceNodeNotificationDeliveriesArgs = { + page?: InputMaybe; + pageSize?: InputMaybe; + verifier?: InputMaybe; +}; + export const DeviceResolverAllKeys = { CreatedAt: 'createdAt', ExpoPushToken: 'expoPushToken', @@ -298,7 +299,7 @@ export type DeviceResolverKeyedDateFilterItem = { readonly field: DeviceResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type DeviceResolverKeyedIsNullFilterItem = { @@ -331,28 +332,23 @@ export const DeviceResolverStringFilterKeys = { } as const; export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; -export type DeviceResource = { - readonly __typename?: 'DeviceResource'; +export type EventNode = Node & { + readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; - readonly expoPushToken?: Maybe; - readonly lastLoggedInUser?: Maybe; - readonly lastLogin?: Maybe; - readonly notificationDeliveries: ReadonlyArray; + readonly description?: Maybe; + readonly id: Scalars['ID']['output']; + readonly images: ReadonlyArray; + readonly location?: Maybe; + readonly occurrences: ReadonlyArray; + readonly summary?: Maybe; + readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; - -export type DeviceResourceNotificationDeliveriesArgs = { - page?: InputMaybe; - pageSize?: InputMaybe; - verifier?: InputMaybe; -}; - -export type EventOccurrenceResource = { - readonly __typename?: 'EventOccurrenceResource'; +export type EventOccurrenceNode = { + readonly __typename?: 'EventOccurrenceNode'; readonly fullDay: Scalars['Boolean']['output']; - readonly interval: Scalars['LuxonDateRange']['output']; + readonly interval: IntervalIso; readonly uuid: Scalars['ID']['output']; }; @@ -385,7 +381,7 @@ export type EventResolverKeyedDateFilterItem = { readonly field: EventResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type EventResolverKeyedIsNullFilterItem = { @@ -421,80 +417,73 @@ export const EventResolverStringFilterKeys = { } as const; export type EventResolverStringFilterKeys = typeof EventResolverStringFilterKeys[keyof typeof EventResolverStringFilterKeys]; -export type EventResource = { - readonly __typename?: 'EventResource'; - readonly createdAt?: Maybe; - readonly description?: Maybe; - readonly images: ReadonlyArray; - readonly location?: Maybe; - readonly occurrences: ReadonlyArray; - readonly summary?: Maybe; - readonly title: Scalars['String']['output']; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - -export type FeedResource = { - readonly __typename?: 'FeedResource'; +export type FeedNode = Node & { + readonly __typename?: 'FeedNode'; readonly createdAt?: Maybe; - readonly image?: Maybe; + readonly id: Scalars['ID']['output']; + readonly image?: Maybe; readonly textContent?: Maybe; readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export type GetAllConfigurationsResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetAllConfigurationsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; }; export type GetConfigurationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetConfigurationByUuidResponse'; - readonly data: ConfigurationResource; + readonly data: ConfigurationNode; readonly ok: Scalars['Boolean']['output']; }; export type GetDeviceByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetDeviceByUuidResponse'; - readonly data: DeviceResource; + readonly data: DeviceNode; readonly ok: Scalars['Boolean']['output']; }; export type GetEventByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetEventByUuidResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; }; export type GetImageByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetImageByUuidResponse'; - readonly data: ImageResource; + readonly data: ImageNode; + readonly ok: Scalars['Boolean']['output']; +}; + +export type GetMembershipResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { + readonly __typename?: 'GetMembershipResponse'; + readonly data?: Maybe; readonly ok: Scalars['Boolean']['output']; }; export type GetNotificationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetNotificationByUuidResponse'; - readonly data: NotificationResource; + readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; }; export type GetPeopleResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPeopleResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; }; export type GetPersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPersonResponse'; - readonly data?: Maybe; + readonly data?: Maybe; readonly ok: Scalars['Boolean']['output']; }; export type GetPointEntryByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPointEntryByUuidResponse'; - readonly data: PointEntryResource; + readonly data: PointEntryNode; readonly ok: Scalars['Boolean']['output']; }; @@ -503,6 +492,19 @@ export type GraphQlBaseResponse = { readonly ok: Scalars['Boolean']['output']; }; +export type ImageNode = Node & { + readonly __typename?: 'ImageNode'; + readonly alt?: Maybe; + readonly createdAt?: Maybe; + readonly height: Scalars['Int']['output']; + readonly id: Scalars['ID']['output']; + readonly mimeType: Scalars['String']['output']; + readonly thumbHash?: Maybe; + readonly updatedAt?: Maybe; + readonly url?: Maybe; + readonly width: Scalars['Int']['output']; +}; + export const ImageResolverAllKeys = { Alt: 'alt', CreatedAt: 'createdAt', @@ -525,7 +527,7 @@ export type ImageResolverKeyedDateFilterItem = { readonly field: ImageResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type ImageResolverKeyedIsNullFilterItem = { @@ -574,22 +576,20 @@ export const ImageResolverStringFilterKeys = { } as const; export type ImageResolverStringFilterKeys = typeof ImageResolverStringFilterKeys[keyof typeof ImageResolverStringFilterKeys]; -export type ImageResource = { - readonly __typename?: 'ImageResource'; - readonly alt?: Maybe; - readonly createdAt?: Maybe; - readonly height: Scalars['Int']['output']; - readonly mimeType: Scalars['String']['output']; - readonly thumbHash?: Maybe; - readonly updatedAt?: Maybe; - readonly url?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly width: Scalars['Int']['output']; +export type IntervalIso = { + readonly __typename?: 'IntervalISO'; + readonly end: Scalars['DateTimeISO']['output']; + readonly start: Scalars['DateTimeISO']['output']; +}; + +export type IntervalIsoInput = { + readonly end: Scalars['DateTimeISO']['input']; + readonly start: Scalars['DateTimeISO']['input']; }; export type ListDevicesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListDevicesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -601,7 +601,7 @@ export type ListDevicesResponse = AbstractGraphQlArrayOkResponse & AbstractGraph export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListEventsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -613,7 +613,7 @@ export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListImagesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -625,7 +625,7 @@ export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListMarathonsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListMarathonsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -637,7 +637,7 @@ export type ListMarathonsResponse = AbstractGraphQlArrayOkResponse & AbstractGra export type ListNotificationDeliveriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListNotificationDeliveriesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -649,7 +649,7 @@ export type ListNotificationDeliveriesResponse = AbstractGraphQlArrayOkResponse export type ListNotificationsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListNotificationsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -661,7 +661,7 @@ export type ListNotificationsResponse = AbstractGraphQlArrayOkResponse & Abstrac export type ListPeopleResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPeopleResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -673,7 +673,7 @@ export type ListPeopleResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListPointEntriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPointEntriesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -685,7 +685,7 @@ export type ListPointEntriesResponse = AbstractGraphQlArrayOkResponse & Abstract export type ListPointOpportunitiesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPointOpportunitiesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -697,7 +697,7 @@ export type ListPointOpportunitiesResponse = AbstractGraphQlArrayOkResponse & Ab export type ListTeamsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListTeamsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -710,20 +710,31 @@ export type ListTeamsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQl export type LoginState = { readonly __typename?: 'LoginState'; readonly authSource: AuthSource; + readonly dbRole: DbRole; readonly loggedIn: Scalars['Boolean']['output']; - readonly role: RoleResource; }; -export type MarathonHourResource = { - readonly __typename?: 'MarathonHourResource'; +export type MarathonHourNode = Node & { + readonly __typename?: 'MarathonHourNode'; readonly createdAt?: Maybe; readonly details?: Maybe; readonly durationInfo: Scalars['String']['output']; - readonly mapImages: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly mapImages: ReadonlyArray; readonly shownStartingAt: Scalars['DateTimeISO']['output']; readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; +}; + +export type MarathonNode = Node & { + readonly __typename?: 'MarathonNode'; + readonly createdAt?: Maybe; + readonly endDate?: Maybe; + readonly hours: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly startDate?: Maybe; + readonly updatedAt?: Maybe; + readonly year: Scalars['String']['output']; }; export const MarathonResolverAllKeys = { @@ -750,7 +761,7 @@ export type MarathonResolverKeyedDateFilterItem = { readonly field: MarathonResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type MarathonResolverKeyedIsNullFilterItem = { @@ -760,43 +771,33 @@ export type MarathonResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type MarathonResource = { - readonly __typename?: 'MarathonResource'; +export type MembershipNode = Node & { + readonly __typename?: 'MembershipNode'; readonly createdAt?: Maybe; - readonly endDate: Scalars['DateTimeISO']['output']; - readonly hours: ReadonlyArray; - readonly startDate: Scalars['DateTimeISO']['output']; + readonly id: Scalars['ID']['output']; + readonly person: PersonNode; + readonly position: MembershipPositionType; + readonly team: TeamNode; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly year: Scalars['String']['output']; }; export { MembershipPositionType }; -export type MembershipResource = { - readonly __typename?: 'MembershipResource'; - readonly createdAt?: Maybe; - readonly person: PersonResource; - readonly position: MembershipPositionType; - readonly team: TeamResource; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export type Mutation = { readonly __typename?: 'Mutation'; readonly abortScheduledNotification: AbortScheduledNotificationResponse; readonly acknowledgeDeliveryIssue: AcknowledgeDeliveryIssueResponse; readonly addExistingImageToEvent: AddEventImageResponse; - readonly addMap: MarathonHourResource; - readonly attachImageToFeedItem: FeedResource; + readonly addMap: MarathonHourNode; + readonly addPersonToTeam: GetMembershipResponse; + readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; readonly createEvent: CreateEventResponse; - readonly createFeedItem: FeedResource; - readonly createImage: ImageResource; - readonly createMarathon: MarathonResource; - readonly createMarathonHour: MarathonHourResource; + readonly createFeedItem: FeedNode; + readonly createImage: ImageNode; + readonly createMarathon: MarathonNode; + readonly createMarathonHour: MarathonHourNode; readonly createPerson: CreatePersonResponse; readonly createPointEntry: CreatePointEntryResponse; readonly createPointOpportunity: CreatePointOpportunityResponse; @@ -815,17 +816,17 @@ export type Mutation = { readonly deleteTeam: DeleteTeamResponse; readonly registerDevice: RegisterDeviceResponse; readonly removeImageFromEvent: RemoveEventImageResponse; - readonly removeImageFromFeedItem: FeedResource; + readonly removeImageFromFeedItem: FeedNode; readonly removeMap: Scalars['Void']['output']; readonly scheduleNotification: ScheduleNotificationResponse; /** Send a notification immediately. */ readonly sendNotification: SendNotificationResponse; readonly setEvent: SetEventResponse; - readonly setFeedItem: FeedResource; - readonly setImageAltText: ImageResource; - readonly setImageUrl: ImageResource; - readonly setMarathon: MarathonResource; - readonly setMarathonHour: MarathonHourResource; + readonly setFeedItem: FeedNode; + readonly setImageAltText: ImageNode; + readonly setImageUrl: ImageNode; + readonly setMarathon: MarathonNode; + readonly setMarathonHour: MarathonHourNode; readonly setPerson: GetPersonResponse; readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; @@ -855,6 +856,12 @@ export type MutationAddMapArgs = { }; +export type MutationAddPersonToTeamArgs = { + personUuid: Scalars['String']['input']; + teamUuid: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -914,6 +921,7 @@ export type MutationCreatePointOpportunityArgs = { export type MutationCreateTeamArgs = { input: CreateTeamInput; + marathon: Scalars['String']['input']; }; @@ -1071,6 +1079,10 @@ export type MutationStageNotificationArgs = { url?: InputMaybe; }; +export type Node = { + readonly id: Scalars['ID']['output']; +}; + export type NotificationAudienceInput = { readonly all?: InputMaybe; readonly memberOfTeamType?: InputMaybe; @@ -1089,6 +1101,22 @@ export type NotificationDeliveryIssueCount = { readonly Unknown: Scalars['Int']['output']; }; +export type NotificationDeliveryNode = Node & { + readonly __typename?: 'NotificationDeliveryNode'; + /** A unique identifier corresponding the group of notifications this was sent to Expo with. */ + readonly chunkUuid?: Maybe; + readonly createdAt?: Maybe; + /** Any error message returned by Expo when sending the notification. */ + readonly deliveryError?: Maybe; + readonly id: Scalars['ID']['output']; + readonly notification: NotificationNode; + /** The time the server received a delivery receipt from the user. */ + readonly receiptCheckedAt?: Maybe; + /** The time the server sent the notification to Expo for delivery. */ + readonly sentAt?: Maybe; + readonly updatedAt?: Maybe; +}; + export const NotificationDeliveryResolverAllKeys = { CreatedAt: 'createdAt', DeliveryError: 'deliveryError', @@ -1113,7 +1141,7 @@ export type NotificationDeliveryResolverKeyedDateFilterItem = { readonly field: NotificationDeliveryResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type NotificationDeliveryResolverKeyedIsNullFilterItem = { @@ -1123,20 +1151,22 @@ export type NotificationDeliveryResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type NotificationDeliveryResource = { - readonly __typename?: 'NotificationDeliveryResource'; - /** A unique identifier corresponding the group of notifications this was sent to Expo with. */ - readonly chunkUuid?: Maybe; +export type NotificationNode = Node & { + readonly __typename?: 'NotificationNode'; + readonly body: Scalars['String']['output']; readonly createdAt?: Maybe; - /** Any error message returned by Expo when sending the notification. */ - readonly deliveryError?: Maybe; - readonly notification: NotificationResource; - /** The time the server received a delivery receipt from the user. */ - readonly receiptCheckedAt?: Maybe; - /** The time the server sent the notification to Expo for delivery. */ - readonly sentAt?: Maybe; + readonly deliveryCount: Scalars['Int']['output']; + readonly deliveryIssue?: Maybe; + readonly deliveryIssueAcknowledgedAt?: Maybe; + readonly deliveryIssueCount: NotificationDeliveryIssueCount; + readonly id: Scalars['ID']['output']; + /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ + readonly sendAt?: Maybe; + /** The time the server started sending the notification. */ + readonly startedSendingAt?: Maybe; + readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; + readonly url?: Maybe; }; export const NotificationResolverAllKeys = { @@ -1165,7 +1195,7 @@ export type NotificationResolverKeyedDateFilterItem = { readonly field: NotificationResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type NotificationResolverKeyedIsNullFilterItem = { @@ -1204,26 +1234,23 @@ export const NotificationResolverStringFilterKeys = { } as const; export type NotificationResolverStringFilterKeys = typeof NotificationResolverStringFilterKeys[keyof typeof NotificationResolverStringFilterKeys]; -export type NotificationResource = { - readonly __typename?: 'NotificationResource'; - readonly body: Scalars['String']['output']; +export { NumericComparator }; + +export type PersonNode = Node & { + readonly __typename?: 'PersonNode'; + /** @deprecated Use teams instead and filter by position */ + readonly captaincies: ReadonlyArray; + readonly committees: ReadonlyArray; readonly createdAt?: Maybe; - readonly deliveryCount: Scalars['Int']['output']; - readonly deliveryIssue?: Maybe; - readonly deliveryIssueAcknowledgedAt?: Maybe; - readonly deliveryIssueCount: NotificationDeliveryIssueCount; - /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ - readonly sendAt?: Maybe; - /** The time the server started sending the notification. */ - readonly startedSendingAt?: Maybe; - readonly title: Scalars['String']['output']; + readonly dbRole: DbRole; + readonly email: Scalars['String']['output']; + readonly id: Scalars['ID']['output']; + readonly linkblue?: Maybe; + readonly name?: Maybe; + readonly teams: ReadonlyArray; readonly updatedAt?: Maybe; - readonly url?: Maybe; - readonly uuid: Scalars['ID']['output']; }; -export { NumericComparator }; - export const PersonResolverAllKeys = { CommitteeName: 'committeeName', CommitteeRole: 'committeeRole', @@ -1273,20 +1300,16 @@ export const PersonResolverStringFilterKeys = { } as const; export type PersonResolverStringFilterKeys = typeof PersonResolverStringFilterKeys[keyof typeof PersonResolverStringFilterKeys]; -export type PersonResource = { - readonly __typename?: 'PersonResource'; - /** @deprecated This is now provided on the AuthIdPair resource. */ - readonly authIds: ReadonlyArray; - /** @deprecated Use teams instead and filter by position */ - readonly captaincies: ReadonlyArray; +export type PointEntryNode = Node & { + readonly __typename?: 'PointEntryNode'; + readonly comment?: Maybe; readonly createdAt?: Maybe; - readonly email: Scalars['String']['output']; - readonly linkblue?: Maybe; - readonly name?: Maybe; - readonly role: RoleResource; - readonly teams: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly personFrom?: Maybe; + readonly pointOpportunity?: Maybe; + readonly points: Scalars['Int']['output']; + readonly team: TeamNode; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export const PointEntryResolverAllKeys = { @@ -1308,7 +1331,7 @@ export type PointEntryResolverKeyedDateFilterItem = { readonly field: PointEntryResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type PointEntryResolverKeyedIsNullFilterItem = { @@ -1318,16 +1341,15 @@ export type PointEntryResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type PointEntryResource = { - readonly __typename?: 'PointEntryResource'; - readonly comment?: Maybe; +export type PointOpportunityNode = Node & { + readonly __typename?: 'PointOpportunityNode'; readonly createdAt?: Maybe; - readonly personFrom?: Maybe; - readonly pointOpportunity?: Maybe; - readonly points: Scalars['Int']['output']; - readonly team: TeamResource; + readonly event?: Maybe; + readonly id: Scalars['ID']['output']; + readonly name: Scalars['String']['output']; + readonly opportunityDate?: Maybe; + readonly type: TeamType; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export const PointOpportunityResolverAllKeys = { @@ -1353,7 +1375,7 @@ export type PointOpportunityResolverKeyedDateFilterItem = { readonly field: PointOpportunityResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type PointOpportunityResolverKeyedIsNullFilterItem = { @@ -1391,38 +1413,27 @@ export const PointOpportunityResolverStringFilterKeys = { } as const; export type PointOpportunityResolverStringFilterKeys = typeof PointOpportunityResolverStringFilterKeys[keyof typeof PointOpportunityResolverStringFilterKeys]; -export type PointOpportunityResource = { - readonly __typename?: 'PointOpportunityResource'; - readonly createdAt?: Maybe; - readonly event?: Maybe; - readonly name: Scalars['String']['output']; - readonly opportunityDate?: Maybe; - readonly type: TeamType; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export type Query = { readonly __typename?: 'Query'; readonly activeConfiguration: GetConfigurationByUuidResponse; readonly allConfigurations: GetAllConfigurationsResponse; - readonly currentMarathon?: Maybe; - readonly currentMarathonHour?: Maybe; + readonly currentMarathon?: Maybe; + readonly currentMarathonHour?: Maybe; readonly device: GetDeviceByUuidResponse; readonly devices: ListDevicesResponse; readonly event: GetEventByUuidResponse; readonly events: ListEventsResponse; - readonly feed: ReadonlyArray; + readonly feed: ReadonlyArray; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; readonly listPeople: ListPeopleResponse; readonly loginState: LoginState; - readonly marathon: MarathonResource; - readonly marathonForYear: MarathonResource; - readonly marathonHour: MarathonHourResource; + readonly marathon: MarathonNode; + readonly marathonForYear: MarathonNode; + readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; - readonly nextMarathon?: Maybe; + readonly nextMarathon?: Maybe; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -1689,7 +1700,7 @@ export type RegisterDeviceInput = { export type RegisterDeviceResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'RegisterDeviceResponse'; - readonly data: DeviceResource; + readonly data: DeviceNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1699,19 +1710,6 @@ export type RemoveEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRe readonly ok: Scalars['Boolean']['output']; }; -export type RoleResource = { - readonly __typename?: 'RoleResource'; - readonly committeeIdentifier?: Maybe; - readonly committeeRole?: Maybe; - readonly dbRole: DbRole; -}; - -export type RoleResourceInput = { - readonly committeeIdentifier?: InputMaybe; - readonly committeeRole?: InputMaybe; - readonly dbRole?: DbRole; -}; - export type ScheduleNotificationResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'ScheduleNotificationResponse'; readonly data: Scalars['Boolean']['output']; @@ -1734,14 +1732,14 @@ export type SetEventInput = { export type SetEventOccurrenceInput = { readonly fullDay: Scalars['Boolean']['input']; - readonly interval: Scalars['LuxonDateRange']['input']; + readonly interval: IntervalIsoInput; /** If updating an existing occurrence, the UUID of the occurrence to update */ readonly uuid?: InputMaybe; }; export type SetEventResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SetEventResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1765,17 +1763,17 @@ export type SetMarathonInput = { export type SetPersonInput = { readonly captainOf?: InputMaybe>; + readonly dbRole?: InputMaybe; readonly email?: InputMaybe; readonly linkblue?: InputMaybe; readonly memberOf?: InputMaybe>; readonly name?: InputMaybe; - readonly role?: InputMaybe; }; export type SetPointOpportunityInput = { readonly eventUuid?: InputMaybe; readonly name?: InputMaybe; - readonly opportunityDate?: InputMaybe; + readonly opportunityDate?: InputMaybe; readonly type?: InputMaybe; }; @@ -1789,13 +1787,13 @@ export type SetTeamInput = { export type SinglePointOpportunityResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SinglePointOpportunityResponse'; - readonly data: PointOpportunityResource; + readonly data: PointOpportunityNode; readonly ok: Scalars['Boolean']['output']; }; export type SingleTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SingleTeamResponse'; - readonly data: TeamResource; + readonly data: TeamNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1803,7 +1801,7 @@ export { SortDirection }; export type StageNotificationResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'StageNotificationResponse'; - readonly data: NotificationResource; + readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -1812,6 +1810,21 @@ export { StringComparator }; export { TeamLegacyStatus }; +export type TeamNode = Node & { + readonly __typename?: 'TeamNode'; + /** @deprecated Just query the members field and filter by role */ + readonly captains: ReadonlyArray; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly legacyStatus: TeamLegacyStatus; + readonly members: ReadonlyArray; + readonly name: Scalars['String']['output']; + readonly pointEntries: ReadonlyArray; + readonly totalPoints: Scalars['Int']['output']; + readonly type: TeamType; + readonly updatedAt?: Maybe; +}; + export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', MarathonYear: 'marathonYear', @@ -1857,38 +1870,21 @@ export const TeamResolverStringFilterKeys = { } as const; export type TeamResolverStringFilterKeys = typeof TeamResolverStringFilterKeys[keyof typeof TeamResolverStringFilterKeys]; -export type TeamResource = { - readonly __typename?: 'TeamResource'; - /** @deprecated Just query the members field and filter by role */ - readonly captains: ReadonlyArray; - readonly createdAt?: Maybe; - readonly legacyStatus: TeamLegacyStatus; - readonly marathonYear: Scalars['String']['output']; - readonly members: ReadonlyArray; - readonly name: Scalars['String']['output']; - readonly persistentIdentifier?: Maybe; - readonly pointEntries: ReadonlyArray; - readonly totalPoints: Scalars['Int']['output']; - readonly type: TeamType; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export { TeamType }; -export type ImageViewFragmentFragment = { readonly __typename?: 'ImageResource', readonly uuid: string, readonly url?: URL | string | null, readonly thumbHash?: string | null, readonly alt?: string | null, readonly width: number, readonly height: number, readonly mimeType: string } & { ' $fragmentName'?: 'ImageViewFragmentFragment' }; +export type ImageViewFragmentFragment = { readonly __typename?: 'ImageNode', readonly id: string, readonly url?: URL | string | null, readonly thumbHash?: string | null, readonly alt?: string | null, readonly width: number, readonly height: number, readonly mimeType: string } & { ' $fragmentName'?: 'ImageViewFragmentFragment' }; -export type SimpleConfigFragment = { readonly __typename?: 'ConfigurationResource', readonly uuid: string, readonly key: string, readonly value: string } & { ' $fragmentName'?: 'SimpleConfigFragment' }; +export type SimpleConfigFragment = { readonly __typename?: 'ConfigurationNode', readonly id: string, readonly key: string, readonly value: string } & { ' $fragmentName'?: 'SimpleConfigFragment' }; export type FullConfigFragment = ( - { readonly __typename?: 'ConfigurationResource', readonly validAfter?: string | null, readonly validUntil?: string | null, readonly createdAt?: Date | string | null } + { readonly __typename?: 'ConfigurationNode', readonly validAfter?: Date | string | null, readonly validUntil?: Date | string | null, readonly createdAt?: Date | string | null } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } ) & { ' $fragmentName'?: 'FullConfigFragment' }; -export type NotificationFragmentFragment = { readonly __typename?: 'NotificationResource', readonly uuid: string, readonly title: string, readonly body: string, readonly url?: URL | string | null } & { ' $fragmentName'?: 'NotificationFragmentFragment' }; +export type NotificationFragmentFragment = { readonly __typename?: 'NotificationNode', readonly id: string, readonly title: string, readonly body: string, readonly url?: URL | string | null } & { ' $fragmentName'?: 'NotificationFragmentFragment' }; -export type NotificationDeliveryFragmentFragment = { readonly __typename?: 'NotificationDeliveryResource', readonly uuid: string, readonly sentAt?: Date | string | null, readonly notification: ( - { readonly __typename?: 'NotificationResource' } +export type NotificationDeliveryFragmentFragment = { readonly __typename?: 'NotificationDeliveryNode', readonly id: string, readonly sentAt?: Date | string | null, readonly notification: ( + { readonly __typename?: 'NotificationNode' } & { ' $fragmentRefs'?: { 'NotificationFragmentFragment': NotificationFragmentFragment } } ) } & { ' $fragmentName'?: 'NotificationDeliveryFragmentFragment' }; @@ -1896,35 +1892,35 @@ export type UseAllowedLoginTypesQueryVariables = Exact<{ [key: string]: never; } export type UseAllowedLoginTypesQuery = { readonly __typename?: 'Query', readonly activeConfiguration: { readonly __typename?: 'GetConfigurationByUuidResponse', readonly data: ( - { readonly __typename?: 'ConfigurationResource' } + { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } ) } }; export type MarathonTimeQueryVariables = Exact<{ [key: string]: never; }>; -export type MarathonTimeQuery = { readonly __typename?: 'Query', readonly nextMarathon?: { readonly __typename?: 'MarathonResource', readonly startDate: Date | string, readonly endDate: Date | string } | null }; +export type MarathonTimeQuery = { readonly __typename?: 'Query', readonly nextMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null }; export type UseTabBarConfigQueryVariables = Exact<{ [key: string]: never; }>; export type UseTabBarConfigQuery = { readonly __typename?: 'Query', readonly activeConfiguration: { readonly __typename?: 'GetConfigurationByUuidResponse', readonly data: ( - { readonly __typename?: 'ConfigurationResource' } + { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } - ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly linkblue?: string | null } | null } }; + ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly linkblue?: string | null } | null } }; export type TriviaCrackQueryVariables = Exact<{ [key: string]: never; }>; export type TriviaCrackQuery = { readonly __typename?: 'Query', readonly activeConfiguration: { readonly __typename?: 'GetConfigurationByUuidResponse', readonly data: ( - { readonly __typename?: 'ConfigurationResource' } + { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } - ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly team: { readonly __typename?: 'TeamResource', readonly type: TeamType, readonly name: string } }> } | null } }; + ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: { readonly __typename?: 'TeamNode', readonly type: TeamType, readonly name: string } }> } | null } }; export type AuthStateQueryVariables = Exact<{ [key: string]: never; }>; -export type AuthStateQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly uuid: string } | null }, readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly authSource: AuthSource, readonly role: { readonly __typename?: 'RoleResource', readonly dbRole: DbRole, readonly committeeIdentifier?: CommitteeIdentifier | null, readonly committeeRole?: CommitteeRole | null } } }; +export type AuthStateQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string } | null }, readonly loginState: { readonly __typename?: 'LoginState', readonly dbRole: DbRole, readonly loggedIn: boolean, readonly authSource: AuthSource } }; export type SetDeviceMutationVariables = Exact<{ input: RegisterDeviceInput; @@ -1933,7 +1929,7 @@ export type SetDeviceMutationVariables = Exact<{ export type SetDeviceMutation = { readonly __typename?: 'Mutation', readonly registerDevice: { readonly __typename?: 'RegisterDeviceResponse', readonly ok: boolean } }; -export type EventScreenFragmentFragment = { readonly __typename?: 'EventResource', readonly uuid: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceResource', readonly uuid: string, readonly interval: string, readonly fullDay: boolean }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageResource', readonly thumbHash?: string | null, readonly url?: URL | string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string }> } & { ' $fragmentName'?: 'EventScreenFragmentFragment' }; +export type EventScreenFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly thumbHash?: string | null, readonly url?: URL | string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string }> } & { ' $fragmentName'?: 'EventScreenFragmentFragment' }; export type DeviceNotificationsQueryVariables = Exact<{ deviceUuid: Scalars['String']['input']; @@ -1943,14 +1939,14 @@ export type DeviceNotificationsQueryVariables = Exact<{ }>; -export type DeviceNotificationsQuery = { readonly __typename?: 'Query', readonly device: { readonly __typename?: 'GetDeviceByUuidResponse', readonly data: { readonly __typename?: 'DeviceResource', readonly notificationDeliveries: ReadonlyArray<( - { readonly __typename?: 'NotificationDeliveryResource' } +export type DeviceNotificationsQuery = { readonly __typename?: 'Query', readonly device: { readonly __typename?: 'GetDeviceByUuidResponse', readonly data: { readonly __typename?: 'DeviceNode', readonly notificationDeliveries: ReadonlyArray<( + { readonly __typename?: 'NotificationDeliveryNode' } & { ' $fragmentRefs'?: { 'NotificationDeliveryFragmentFragment': NotificationDeliveryFragmentFragment } } )> } } }; -export type ProfileScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly authSource: AuthSource, readonly role: { readonly __typename?: 'RoleResource', readonly committeeIdentifier?: CommitteeIdentifier | null, readonly committeeRole?: CommitteeRole | null, readonly dbRole: DbRole } } & { ' $fragmentName'?: 'ProfileScreenAuthFragmentFragment' }; +export type ProfileScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly dbRole: DbRole, readonly authSource: AuthSource } & { ' $fragmentName'?: 'ProfileScreenAuthFragmentFragment' }; -export type ProfileScreenUserFragmentFragment = { readonly __typename?: 'PersonResource', readonly name?: string | null, readonly linkblue?: string | null, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamResource', readonly name: string } }> } & { ' $fragmentName'?: 'ProfileScreenUserFragmentFragment' }; +export type ProfileScreenUserFragmentFragment = { readonly __typename?: 'PersonNode', readonly name?: string | null, readonly linkblue?: string | null, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly name: string } }> } & { ' $fragmentName'?: 'ProfileScreenUserFragmentFragment' }; export type RootScreenDocumentQueryVariables = Exact<{ [key: string]: never; }>; @@ -1959,30 +1955,30 @@ export type RootScreenDocumentQuery = { readonly __typename?: 'Query', readonly { readonly __typename?: 'LoginState' } & { ' $fragmentRefs'?: { 'ProfileScreenAuthFragmentFragment': ProfileScreenAuthFragmentFragment;'RootScreenAuthFragmentFragment': RootScreenAuthFragmentFragment } } ), readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonResource' } + { readonly __typename?: 'PersonNode' } & { ' $fragmentRefs'?: { 'ProfileScreenUserFragmentFragment': ProfileScreenUserFragmentFragment } } ) | null } }; -export type RootScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly role: { readonly __typename?: 'RoleResource', readonly dbRole: DbRole } } & { ' $fragmentName'?: 'RootScreenAuthFragmentFragment' }; +export type RootScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly dbRole: DbRole } & { ' $fragmentName'?: 'RootScreenAuthFragmentFragment' }; export type EventsQueryVariables = Exact<{ - earliestTimestamp: Scalars['LuxonDateTime']['input']; - lastTimestamp: Scalars['LuxonDateTime']['input']; + earliestTimestamp: Scalars['DateTimeISO']['input']; + lastTimestamp: Scalars['DateTimeISO']['input']; }>; export type EventsQuery = { readonly __typename?: 'Query', readonly events: { readonly __typename?: 'ListEventsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'EventResource' } + { readonly __typename?: 'EventNode' } & { ' $fragmentRefs'?: { 'EventScreenFragmentFragment': EventScreenFragmentFragment } } )> } }; export type ServerFeedQueryVariables = Exact<{ [key: string]: never; }>; -export type ServerFeedQuery = { readonly __typename?: 'Query', readonly feed: ReadonlyArray<{ readonly __typename?: 'FeedResource', readonly uuid: string, readonly title: string, readonly createdAt?: Date | string | null, readonly textContent?: string | null, readonly image?: { readonly __typename?: 'ImageResource', readonly url?: URL | string | null, readonly alt?: string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null } | null }> }; +export type ServerFeedQuery = { readonly __typename?: 'Query', readonly feed: ReadonlyArray<{ readonly __typename?: 'FeedNode', readonly id: string, readonly title: string, readonly createdAt?: Date | string | null, readonly textContent?: string | null, readonly image?: { readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly alt?: string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null } | null }> }; -export type HourScreenFragmentFragment = { readonly __typename?: 'MarathonHourResource', readonly uuid: string, readonly title: string, readonly details?: string | null, readonly durationInfo: string, readonly mapImages: ReadonlyArray<( - { readonly __typename?: 'ImageResource' } +export type HourScreenFragmentFragment = { readonly __typename?: 'MarathonHourNode', readonly id: string, readonly title: string, readonly details?: string | null, readonly durationInfo: string, readonly mapImages: ReadonlyArray<( + { readonly __typename?: 'ImageNode' } & { ' $fragmentRefs'?: { 'ImageViewFragmentFragment': ImageViewFragmentFragment } } )> } & { ' $fragmentName'?: 'HourScreenFragmentFragment' }; @@ -1990,60 +1986,60 @@ export type MarathonScreenQueryVariables = Exact<{ [key: string]: never; }>; export type MarathonScreenQuery = { readonly __typename?: 'Query', readonly currentMarathonHour?: ( - { readonly __typename?: 'MarathonHourResource' } + { readonly __typename?: 'MarathonHourNode' } & { ' $fragmentRefs'?: { 'HourScreenFragmentFragment': HourScreenFragmentFragment } } - ) | null, readonly nextMarathon?: { readonly __typename?: 'MarathonResource', readonly startDate: Date | string, readonly endDate: Date | string, readonly hours: ReadonlyArray<( - { readonly __typename?: 'MarathonHourResource' } + ) | null, readonly nextMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null, readonly hours: ReadonlyArray<( + { readonly __typename?: 'MarathonHourNode' } & { ' $fragmentRefs'?: { 'HourScreenFragmentFragment': HourScreenFragmentFragment } } )> } | null }; -export type ScoreBoardFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string, readonly totalPoints: number, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType } & { ' $fragmentName'?: 'ScoreBoardFragmentFragment' }; +export type ScoreBoardFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly totalPoints: number, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType } & { ' $fragmentName'?: 'ScoreBoardFragmentFragment' }; -export type HighlightedTeamFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType } & { ' $fragmentName'?: 'HighlightedTeamFragmentFragment' }; +export type HighlightedTeamFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType } & { ' $fragmentName'?: 'HighlightedTeamFragmentFragment' }; export type ScoreBoardDocumentQueryVariables = Exact<{ type?: InputMaybe | TeamType>; }>; -export type ScoreBoardDocumentQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly team: ( - { readonly __typename?: 'TeamResource' } +export type ScoreBoardDocumentQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: ( + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'HighlightedTeamFragmentFragment': HighlightedTeamFragmentFragment;'MyTeamFragmentFragment': MyTeamFragmentFragment } } ) }> } | null }, readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'TeamResource' } + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'ScoreBoardFragmentFragment': ScoreBoardFragmentFragment } } )> } }; export type ActiveMarathonDocumentQueryVariables = Exact<{ [key: string]: never; }>; -export type ActiveMarathonDocumentQuery = { readonly __typename?: 'Query', readonly currentMarathon?: { readonly __typename?: 'MarathonResource', readonly uuid: string } | null }; - -export type MyTeamFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string, readonly totalPoints: number, readonly pointEntries: ReadonlyArray<{ readonly __typename?: 'PointEntryResource', readonly points: number, readonly personFrom?: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null } | null }>, readonly members: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly position: MembershipPositionType, readonly person: { readonly __typename?: 'PersonResource', readonly linkblue?: string | null, readonly name?: string | null } }> } & { ' $fragmentName'?: 'MyTeamFragmentFragment' }; - -export const SimpleConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const FullConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const NotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; -export const NotificationDeliveryFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; -export const EventScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; -export const ProfileScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]} as unknown as DocumentNode; -export const ProfileScreenUserFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const RootScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]}}]} as unknown as DocumentNode; -export const ImageViewFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; -export const HourScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; -export const ScoreBoardFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const HighlightedTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const MyTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const UseAllowedLoginTypesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useAllowedLoginTypes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"ALLOWED_LOGIN_TYPES","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export type ActiveMarathonDocumentQuery = { readonly __typename?: 'Query', readonly currentMarathon?: { readonly __typename?: 'MarathonNode', readonly id: string } | null }; + +export type MyTeamFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly totalPoints: number, readonly pointEntries: ReadonlyArray<{ readonly __typename?: 'PointEntryNode', readonly points: number, readonly personFrom?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } | null }>, readonly members: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly person: { readonly __typename?: 'PersonNode', readonly linkblue?: string | null, readonly name?: string | null } }> } & { ' $fragmentName'?: 'MyTeamFragmentFragment' }; + +export const SimpleConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const FullConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const NotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; +export const NotificationDeliveryFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; +export const EventScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; +export const ProfileScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]} as unknown as DocumentNode; +export const ProfileScreenUserFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const RootScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; +export const ImageViewFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; +export const HourScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; +export const ScoreBoardFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const HighlightedTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const MyTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const UseAllowedLoginTypesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useAllowedLoginTypes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"ALLOWED_LOGIN_TYPES","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const MarathonTimeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonTime"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; -export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useTabBarConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TAB_BAR_CONFIG","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}}]}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; +export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useTabBarConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TAB_BAR_CONFIG","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; export const SetDeviceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDevice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterDeviceInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerDevice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; -export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"LuxonDateTime"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"LuxonDateTime"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"ASCENDING"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; -export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; -export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; -export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"DESCENDING"},{"kind":"EnumValue","value":"ASCENDING"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const ActiveMarathonDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathonDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; +export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"ASCENDING"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; +export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; +export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; +export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"DESCENDING"},{"kind":"EnumValue","value":"ASCENDING"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ActiveMarathonDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathonDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/utility/time/intervalTools.ts b/packages/common/lib/utility/time/intervalTools.ts index 9a09040d..f917c01e 100644 --- a/packages/common/lib/utility/time/intervalTools.ts +++ b/packages/common/lib/utility/time/intervalTools.ts @@ -1,5 +1,4 @@ -import type { Interval } from "luxon"; -import { DateTime } from "luxon"; +import { DateTime, Interval } from "luxon"; type ValidInterval = Interval & { start: NonNullable; @@ -28,21 +27,21 @@ export function validateInterval( } export function dateTimeFromSomething( - something: string | number | Date | DateTime + something: string | number | Date | DateTime ): DateTime; export function dateTimeFromSomething(something: null): null; export function dateTimeFromSomething(something: undefined): undefined; export function dateTimeFromSomething( - something: string | number | Date | DateTime | null + something: string | number | Date | DateTime | null ): DateTime | null; export function dateTimeFromSomething( - something: string | number | Date | DateTime | undefined + something: string | number | Date | DateTime | undefined ): DateTime | undefined; export function dateTimeFromSomething( - something: string | number | Date | DateTime | null | undefined + something: string | number | Date | DateTime | null | undefined ): DateTime | null | undefined; export function dateTimeFromSomething( - something: string | number | Date | DateTime | null | undefined + something: string | number | Date | DateTime | null | undefined ): DateTime | null | undefined { if (something == null) { return something; @@ -76,3 +75,72 @@ export function dateTimeFromSomething( return dateTime.isValid ? dateTime : null; } + +export function intervalFromSomething( + something: + | string + | { + start: string | number | Date | DateTime; + end: string | number | Date | DateTime; + } +): Interval | Interval; +export function intervalFromSomething(something: { + start: DateTime; + end: DateTime; +}): Interval; +export function intervalFromSomething(something: null): null; +export function intervalFromSomething(something: undefined): undefined; +export function intervalFromSomething( + something: + | string + | { + start: string | number | Date | DateTime; + end: string | number | Date | DateTime; + } + | null + | undefined +): Interval | Interval | null | undefined; +export function intervalFromSomething( + something: + | string + | { + start: string | number | Date | DateTime; + end: string | number | Date | DateTime; + } + | null +): Interval | Interval | null; +export function intervalFromSomething( + something: + | string + | { + start: string | number | Date | DateTime; + end: string | number | Date | DateTime; + } + | undefined +): Interval | Interval | undefined; +export function intervalFromSomething( + something: + | string + | { + start: string | number | Date | DateTime; + end: string | number | Date | DateTime; + } + | null + | undefined +): Interval | Interval | null | undefined { + if (something == null) { + return something; + } + + let interval = null; + if (typeof something === "string") { + return Interval.fromISO(something); + } else if (typeof something === "object") { + const start = dateTimeFromSomething(something.start); + const end = dateTimeFromSomething(something.end); + + interval = Interval.fromDateTimes(start, end); + } + + return interval; +} diff --git a/packages/mobile/src/common/hooks/useMarathonTime.ts b/packages/mobile/src/common/hooks/useMarathonTime.ts index 04279b07..12044f81 100644 --- a/packages/mobile/src/common/hooks/useMarathonTime.ts +++ b/packages/mobile/src/common/hooks/useMarathonTime.ts @@ -37,25 +37,28 @@ export function useMarathonTime(): { }); const marathonInterval = useMemo(() => { - let startTime: DateTime = DateTime.fromMillis(0); - let endTime: DateTime = DateTime.fromMillis(0); - try { if (data?.nextMarathon) { - startTime = dateTimeFromSomething(data.nextMarathon.startDate); - if (!startTime.isValid) { + const startTime = dateTimeFromSomething(data.nextMarathon.startDate); + if (!startTime?.isValid) { + Logger.warn( + `Unrecognized marathon start time: ${startTime?.toString()}`, + { + source: "useMarathonTime", + } + ); + } + const endTime = dateTimeFromSomething(data.nextMarathon.endDate); + if (!endTime?.isValid) { Logger.warn( - `Unrecognized marathon start time: ${startTime.toString()}`, + `Unrecognized marathon end time: ${endTime?.toString()}`, { source: "useMarathonTime", } ); } - endTime = dateTimeFromSomething(data.nextMarathon.endDate); - if (!endTime.isValid) { - Logger.warn(`Unrecognized marathon end time: ${endTime.toString()}`, { - source: "useMarathonTime", - }); + if (startTime && endTime) { + return { startTime, endTime }; } } } catch (error) { @@ -65,7 +68,11 @@ export function useMarathonTime(): { }); } - return { startTime, endTime } as MarathonTime; + // TODO: find a better indicator of "no marathon" + return { + startTime: DateTime.fromMillis(0), + endTime: DateTime.fromMillis(0), + }; }, [data?.nextMarathon]); return { diff --git a/packages/mobile/src/context/auth.tsx b/packages/mobile/src/context/auth.tsx index 1df5d4b8..e1b05f82 100644 --- a/packages/mobile/src/context/auth.tsx +++ b/packages/mobile/src/context/auth.tsx @@ -1,5 +1,5 @@ import { Logger } from "@common/logger/Logger"; -import { AuthSource, RoleResource, defaultRole } from "@ukdanceblue/common"; +import { AuthSource } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; import type { ReactNode } from "react"; import { createContext, useContext, useEffect } from "react"; @@ -8,7 +8,6 @@ import { useQuery } from "urql"; export interface AuthState { personUuid: string | null; loggedIn: boolean; - role: RoleResource; authSource: AuthSource; ready: boolean; @@ -17,7 +16,6 @@ export interface AuthState { const authStateContext = createContext({ personUuid: null, loggedIn: false, - role: defaultRole, authSource: AuthSource.None, ready: false, @@ -66,11 +64,8 @@ export function AuthStateProvider({ children }: { children: ReactNode }) { return ( { {eventData.occurrences.map((occurrence) => { const highlighted = occurrence.uuid === occurrenceId; - const interval = Interval.fromISO(occurrence.interval); + const interval = intervalFromSomething(occurrence.interval); const { whenString, allDay } = stringifyInterval(interval); return ( diff --git a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts index 46d78ad2..31f7424e 100644 --- a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts +++ b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts @@ -1,6 +1,7 @@ import { universalCatch } from "@common/logging"; import { showMessage, showPrompt } from "@common/util/alertUtils"; import { discoverDefaultCalendar } from "@common/util/calendar"; +import { intervalFromSomething } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; import { getFragmentData } from "@ukdanceblue/common/dist/graphql-client-public"; import type { Event } from "expo-calendar"; @@ -10,7 +11,6 @@ import { getCalendarPermissionsAsync, requestCalendarPermissionsAsync, } from "expo-calendar"; -import { Interval } from "luxon"; import { EventScreenFragment } from "./EventScreenFragment"; @@ -60,7 +60,7 @@ export async function onAddToCalendar( const eventDataToExpoEvent = ( occurrence: (typeof eventData.occurrences)[number] ): Partial => { - const interval = Interval.fromISO(occurrence.interval); + const interval = intervalFromSomething(occurrence.interval); if (!interval.isValid) { throw new Error("Invalid interval"); } @@ -78,7 +78,7 @@ export async function onAddToCalendar( endTimeZone: interval.end.zoneName, organizer: "UK DanceBlue", organizerEmail: "community@danceblue.org", - id: `${eventData.uuid}:${occurrence.uuid}`, + id: `${eventData.id}:${occurrence.uuid}`, }; }; diff --git a/packages/mobile/src/navigation/root/NotificationScreen/NotificationScreen.tsx b/packages/mobile/src/navigation/root/NotificationScreen/NotificationScreen.tsx index 979c6726..09e1d402 100644 --- a/packages/mobile/src/navigation/root/NotificationScreen/NotificationScreen.tsx +++ b/packages/mobile/src/navigation/root/NotificationScreen/NotificationScreen.tsx @@ -50,7 +50,7 @@ function NotificationScreen() { ); let dateString = ""; if (delivery.sentAt != null) { - const date = dateTimeFromSomething(delivery.sentAt) ; + const date = dateTimeFromSomething(delivery.sentAt); dateString = date.toLocaleString(DateTime.DATE_MED); } @@ -137,7 +137,7 @@ function NotificationScreen() { data={notifications} sections={sections} keyExtractor={(data, i) => - getFragmentData(NotificationDeliveryFragment, data)?.uuid ?? + getFragmentData(NotificationDeliveryFragment, data)?.id ?? `notification-${i}` } ListEmptyComponent={() => ( diff --git a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx index 45d86cab..0f8f4fda 100644 --- a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx +++ b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx @@ -90,7 +90,7 @@ const ProfileScreen = ({ } const committeeString = useMemo(() => { - if (authData?.role.dbRole === DbRole.Committee) { + if (authData?.dbRole === DbRole.Committee) { if ( authData.role.committeeIdentifier === CommitteeIdentifier.viceCommittee && diff --git a/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx b/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx index 183d8f38..6a2ac910 100644 --- a/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx +++ b/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx @@ -1,8 +1,9 @@ import { EventScreenFragment } from "@navigation/root/EventScreen/EventScreenFragment"; +import { intervalFromSomething } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; import { getFragmentData } from "@ukdanceblue/common/dist/graphql-client-public"; import { Platform } from "expo-modules-core"; -import { DateTime, Interval } from "luxon"; +import { DateTime } from "luxon"; import { Box, Column, Heading, Row } from "native-base"; import type { MutableRefObject } from "react"; import { useCallback, useMemo } from "react"; @@ -44,7 +45,7 @@ export const EventListRenderItem = ({ } return { ...occurrence, - interval: Interval.fromISO(occurrence.interval), + interval: intervalFromSomething(occurrence.interval), }; }, [occurrenceUuid, eventData.occurrences]); @@ -110,7 +111,7 @@ export const EventListRenderItem = ({ } > {hourScreenData.mapImages.map((image, i) => ( void; }) => { const [secretGestureState, setSecretGestureState] = useState<0 | 1 | 2 | 3>( @@ -27,19 +27,27 @@ export const MarathonCountdownScreen = ({ const { primary } = useThemeColors(); const ordinals = ["th", "st", "nd", "rd"]; // s - const startOrdinal = - ordinals[((marathonStart.day % 100) - 20) % 10] || - ordinals[marathonStart.day % 100] || - ordinals[0]; - const endOrdinal = - ordinals[((marathonEnd.day % 100) - 20) % 10] || - ordinals[marathonEnd.day % 100] || - ordinals[0]; + const startOrdinal = marathonStart + ? ordinals[((marathonStart.day % 100) - 20) % 10] || + ordinals[marathonStart.day % 100] || + ordinals[0] + : null; + const endOrdinal = marathonEnd + ? ordinals[((marathonEnd.day % 100) - 20) % 10] || + ordinals[marathonEnd.day % 100] || + ordinals[0] + : null; // technically this isn't the best way of doing the date but idrc atm - const dateString = `${marathonStart.toFormat("LLLL d")}${startOrdinal} - ${marathonEnd.toFormat("d, yyyy").replace(",", `${endOrdinal},`)}`; + const dateString = + marathonStart && marathonEnd + ? `${marathonStart.toFormat("LLLL d")}${startOrdinal} - ${marathonEnd.toFormat("d, yyyy").replace(",", `${endOrdinal},`)}` + : null; - const timeString = `${marathonStart.toFormat("h:mm a")} - ${marathonEnd.toFormat("h:mm a")}`; + const timeString = + marathonStart && marathonEnd + ? `${marathonStart.toFormat("h:mm a")} - ${marathonEnd.toFormat("h:mm a")}` + : null; return ( - + {marathonStart && ( + + )} { if (hourOverride < 0) { return ( setShowSecretMenu(true)} /> ); @@ -113,10 +113,12 @@ export const MarathonScreen = () => { } else if (lastGoodData?.nextMarathon) { return ( setShowSecretMenu(true)} /> ); diff --git a/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx b/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx index 24d14906..47fa0cc9 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/ScoreBoardScreen/ScoreBoardScreen.tsx @@ -114,11 +114,11 @@ const ScoreBoardScreen = ({ for (const team of filteredData) { newStandingData.push({ name: team.name, - id: team.uuid, + id: team.id, points: team.totalPoints, - highlighted: team.uuid === userTeamData?.uuid, + highlighted: team.id === userTeamData?.id, }); - if (team.uuid === userTeamData?.uuid) { + if (team.id === userTeamData?.id) { setUserTeamRank(newStandingData.length); } } @@ -129,7 +129,7 @@ const ScoreBoardScreen = ({ return ( {mode === "spirit" ? ( - userTeamData?.uuid == null ? ( + userTeamData?.id == null ? ( navigate("MyTeam") : undefined} + onTeamClick={userTeamData?.id ? () => navigate("MyTeam") : undefined} /> ); diff --git a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx index 03d7b780..5bca889e 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx @@ -117,7 +117,7 @@ const SpiritScreen = () => { {() => ( diff --git a/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx b/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx index a05b46b8..4ba5596e 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/TeamScreen/TeamScreen.tsx @@ -58,7 +58,7 @@ const TeamScreen = ({ const entriesRecord = new Map(); for (const entry of team.pointEntries) { const { personFrom, points } = entry; - const { uuid, name, linkblue } = personFrom ?? {}; + const { id: uuid, name, linkblue } = personFrom ?? {}; if (uuid) { const existing = entriesRecord.get(uuid); if (existing == null) { From 40c610794bf8fd391ca7e239d7fdb66eca8937fa Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 17:43:31 +0000 Subject: [PATCH 046/153] Fix remaining direct GraphQL errors --- .../common/lib/graphql-client-admin/gql.ts | 140 ++-- .../lib/graphql-client-admin/graphql.ts | 708 +++++++++--------- .../lib/graphql-client-public/graphql.ts | 1 + .../root/ProfileScreen/ProfileScreen.tsx | 1 + .../src/elements/components/ImagePicker.tsx | 6 +- .../src/elements/components/PersonSearch.tsx | 8 +- .../forms/person/edit/PersonEditorGQL.ts | 6 +- .../create/PointEntryCreatorGQL.ts | 8 +- .../create/PointEntryOpportunityLookup.tsx | 4 +- .../forms/team/create/TeamCreatorGQL.ts | 4 +- .../elements/forms/team/edit/TeamEditorGQL.ts | 6 +- .../src/elements/tables/PeopleTable.tsx | 16 +- .../portal/src/elements/tables/TeamsTable.tsx | 11 +- .../src/elements/viewers/team/TeamViewer.tsx | 46 +- packages/portal/src/hooks/useLoginState.ts | 15 +- .../events/create-event/EventCreatorGQL.ts | 2 +- packages/portal/src/pages/feed/FeedPage.tsx | 8 +- .../pages/images/list/CreateImagePopup.tsx | 4 +- .../marathon/create/useMarathonCreatorForm.ts | 4 +- .../single/edit/useMarathonEditorForm.ts | 10 +- .../view/hour/add/AddMarathonHourPage.tsx | 2 +- .../view/hour/edit/EditMarathonHourPage.tsx | 2 +- .../src/repositories/team/TeamRepository.ts | 8 + packages/server/src/resolvers/TeamResolver.ts | 13 + schema.graphql | 1 + 25 files changed, 533 insertions(+), 501 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index f3260128..8d88b7cb 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -13,71 +13,71 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n uuid\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, - "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, - "\n fragment SingleNotificationFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n": types.SingleNotificationFragmentFragmentDoc, + "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, + "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, + "\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n": types.SingleNotificationFragmentFragmentDoc, "\n mutation CreateNotification(\n $title: String!\n $body: String!\n $audience: NotificationAudienceInput!\n $url: String\n ) {\n stageNotification(\n title: $title\n body: $body\n audience: $audience\n url: $url\n ) {\n uuid\n }\n }\n": types.CreateNotificationDocument, "\n mutation CancelNotificationSchedule($uuid: String!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n": types.CancelNotificationScheduleDocument, "\n mutation DeleteNotification($uuid: String!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n": types.DeleteNotificationDocument, "\n mutation SendNotification($uuid: String!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n": types.SendNotificationDocument, "\n mutation ScheduleNotification($uuid: String!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n": types.ScheduleNotificationDocument, - "\n fragment TeamNameFragment on TeamResource {\n uuid\n name\n }\n": types.TeamNameFragmentFragmentDoc, + "\n fragment TeamNameFragment on TeamNode {\n id\n name\n }\n": types.TeamNameFragmentFragmentDoc, "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n ok\n uuid\n }\n }\n": types.PersonCreatorDocument, - "\n fragment PersonEditorFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n": types.PersonEditorFragmentFragmentDoc, + "\n fragment PersonEditorFragment on PersonNode {\n id\n name\n linkblue\n email\n teams {\n position\n team {\n id\n name\n }\n }\n }\n": types.PersonEditorFragmentFragmentDoc, "\n mutation PersonEditor($uuid: String!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.PersonEditorDocument, - "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n uuid\n }\n }\n }\n": types.CreatePointEntryDocument, - "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n": types.GetPersonByUuidDocument, - "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n uuid\n name\n }\n }\n }\n": types.GetPersonByLinkBlueDocument, - "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n uuid\n name\n }\n }\n }\n": types.SearchPersonByNameDocument, + "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n id\n }\n }\n }\n": types.CreatePointEntryDocument, + "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.GetPersonByUuidDocument, + "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n": types.GetPersonByLinkBlueDocument, + "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n": types.SearchPersonByNameDocument, "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n uuid\n }\n }\n": types.CreatePersonByLinkBlueDocument, - "\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n uuid\n }\n }\n }\n": types.PointEntryOpportunityLookupDocument, + "\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n id\n }\n }\n }\n": types.PointEntryOpportunityLookupDocument, "\n mutation CreatePointOpportunity($input: CreatePointOpportunityInput!) {\n createPointOpportunity(input: $input) {\n uuid\n }\n }\n": types.CreatePointOpportunityDocument, - "\n mutation TeamCreator($input: CreateTeamInput!) {\n createTeam(input: $input) {\n ok\n uuid\n }\n }\n": types.TeamCreatorDocument, - "\n fragment TeamEditorFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n persistentIdentifier\n type\n }\n": types.TeamEditorFragmentFragmentDoc, + "\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n": types.TeamCreatorDocument, + "\n fragment TeamEditorFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n type\n }\n": types.TeamEditorFragmentFragmentDoc, "\n mutation TeamEditor($uuid: String!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.TeamEditorDocument, - "\n fragment PeopleTableFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n": types.PeopleTableFragmentFragmentDoc, + "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n": types.PeopleTableFragmentFragmentDoc, "\n query PeopleTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [PersonResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [PersonResolverKeyedOneOfFilterItem!]\n $stringFilters: [PersonResolverKeyedStringFilterItem!]\n ) {\n listPeople(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...PeopleTableFragment\n }\n }\n }\n": types.PeopleTableDocument, "\n query TeamsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [TeamResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [TeamResolverKeyedOneOfFilterItem!]\n $stringFilters: [TeamResolverKeyedStringFilterItem!]\n ) {\n teams(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...TeamsTableFragment\n }\n }\n }\n": types.TeamsTableDocument, - "\n fragment TeamsTableFragment on TeamResource {\n uuid\n type\n name\n legacyStatus\n marathonYear\n totalPoints\n }\n": types.TeamsTableFragmentFragmentDoc, - "\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryResource {\n uuid\n deliveryError\n receiptCheckedAt\n sentAt\n }\n": types.NotificationDeliveriesTableFragmentFragmentDoc, + "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n": types.TeamsTableFragmentFragmentDoc, + "\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryNode {\n id\n deliveryError\n receiptCheckedAt\n sentAt\n }\n": types.NotificationDeliveriesTableFragmentFragmentDoc, "\n query NotificationDeliveriesTableQuery(\n $notificationId: String!\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationDeliveryResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationDeliveryResolverKeyedIsNullFilterItem!]\n ) {\n notificationDeliveries(\n notificationUuid: $notificationId\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationDeliveriesTableFragment\n }\n }\n }\n": types.NotificationDeliveriesTableQueryDocument, - "\n fragment NotificationsTableFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n": types.NotificationsTableFragmentFragmentDoc, + "\n fragment NotificationsTableFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n": types.NotificationsTableFragmentFragmentDoc, "\n query NotificationsTableQuery(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [NotificationResolverKeyedOneOfFilterItem!]\n $stringFilters: [NotificationResolverKeyedStringFilterItem!]\n ) {\n notifications(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationsTableFragment\n }\n }\n }\n": types.NotificationsTableQueryDocument, "\n mutation DeletePointEntry($uuid: String!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePointEntryDocument, - "\n fragment PointEntryTableFragment on PointEntryResource {\n uuid\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n": types.PointEntryTableFragmentFragmentDoc, + "\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n": types.PointEntryTableFragmentFragmentDoc, "\n mutation DeletePerson($uuid: String!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePersonDocument, - "\n fragment PersonViewerFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n": types.PersonViewerFragmentFragmentDoc, + "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n": types.PersonViewerFragmentFragmentDoc, "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, - "\n fragment TeamViewerFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n totalPoints\n type\n members {\n person {\n uuid\n name\n linkblue\n }\n }\n captains {\n person {\n uuid\n name\n linkblue\n }\n }\n }\n": types.TeamViewerFragmentFragmentDoc, - "\n query LoginState {\n loginState {\n loggedIn\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n }\n": types.LoginStateDocument, + "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, + "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n": types.LoginStateDocument, "\n mutation CommitConfigChanges($changes: [CreateConfigurationInput!]!) {\n createConfigurations(input: $changes) {\n ok\n }\n }\n": types.CommitConfigChangesDocument, - "\n fragment ConfigFragment on ConfigurationResource {\n uuid\n key\n value\n validAfter\n validUntil\n createdAt\n }\n": types.ConfigFragmentFragmentDoc, + "\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n": types.ConfigFragmentFragmentDoc, "\n query ConfigQuery {\n allConfigurations {\n data {\n ...ConfigFragment\n }\n }\n }\n ": types.ConfigQueryDocument, - "\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n uuid\n }\n }\n }\n": types.CreateEventDocument, - "\n fragment EventsTableFragment on EventResource {\n uuid\n title\n description\n occurrences {\n uuid\n interval\n fullDay\n }\n summary\n }\n": types.EventsTableFragmentFragmentDoc, + "\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n id\n }\n }\n }\n": types.CreateEventDocument, + "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n": types.EventsTableFragmentFragmentDoc, "\n query EventsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [EventResolverKeyedDateFilterItem!]\n $isNullFilters: [EventResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [EventResolverKeyedOneOfFilterItem!]\n $stringFilters: [EventResolverKeyedStringFilterItem!]\n ) {\n events(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...EventsTableFragment\n }\n }\n }\n": types.EventsTableDocument, "\n query EditEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.EditEventPageDocument, - "\n fragment EventEditorFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n": types.EventEditorFragmentFragmentDoc, + "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n": types.EventEditorFragmentFragmentDoc, "\n mutation SaveEvent($uuid: String!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.SaveEventDocument, "\n mutation DeleteEvent($uuid: String!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteEventDocument, - "\n fragment EventViewerFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n": types.EventViewerFragmentFragmentDoc, + "\n fragment EventViewerFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n": types.EventViewerFragmentFragmentDoc, "\n query ViewEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n": types.ViewEventPageDocument, - "\n query FeedPage {\n feed(limit: null) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n": types.FeedPageDocument, - "\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n uuid\n }\n }\n": types.CreateFeedItemDocument, + "\n query FeedPage {\n feed(limit: null) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n": types.FeedPageDocument, + "\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n id\n }\n }\n": types.CreateFeedItemDocument, "\n mutation DeleteFeedItem($uuid: String!) {\n deleteFeedItem(feedItemUuid: $uuid)\n }\n": types.DeleteFeedItemDocument, - "\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n uuid\n }\n }\n": types.CreateImageDocument, - "\n fragment ImagesTableFragment on ImageResource {\n uuid\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n": types.ImagesTableFragmentFragmentDoc, + "\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n id\n }\n }\n": types.CreateImageDocument, + "\n fragment ImagesTableFragment on ImageNode {\n id\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n": types.ImagesTableFragmentFragmentDoc, "\n query ImagesTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [ImageResolverKeyedDateFilterItem!]\n $isNullFilters: [ImageResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [ImageResolverKeyedOneOfFilterItem!]\n $stringFilters: [ImageResolverKeyedStringFilterItem!]\n $numericFilters: [ImageResolverKeyedNumericFilterItem!]\n ) {\n images(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n numericFilters: $numericFilters\n ) {\n page\n pageSize\n total\n data {\n ...ImagesTableFragment\n }\n }\n }\n": types.ImagesTableDocument, - "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n uuid\n }\n }\n ": types.CreateMarathonDocument, + "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n id\n }\n }\n ": types.CreateMarathonDocument, "\n query MarathonOverviewPage {\n nextMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n": types.MarathonOverviewPageDocument, - "\n fragment MarathonTableFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n }\n": types.MarathonTableFragmentFragmentDoc, - "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n uuid\n }\n }\n ": types.EditMarathonDocument, + "\n fragment MarathonTableFragment on MarathonNode {\n id\n year\n startDate\n endDate\n }\n": types.MarathonTableFragmentFragmentDoc, + "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n ": types.EditMarathonDocument, "\n query GetMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n ": types.GetMarathonDocument, - "\n fragment MarathonViewerFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n hours {\n uuid\n shownStartingAt\n title\n }\n }\n": types.MarathonViewerFragmentFragmentDoc, + "\n fragment MarathonViewerFragment on MarathonNode {\n id\n year\n startDate\n endDate\n hours {\n id\n shownStartingAt\n title\n }\n }\n": types.MarathonViewerFragmentFragmentDoc, "\n query MarathonPage($marathonUuid: String!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n": types.MarathonPageDocument, - "\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n uuid\n }\n }\n ": types.AddMarathonHourDocument, + "\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n id\n }\n }\n ": types.AddMarathonHourDocument, "\n query EditMarathonHourData($marathonHourUuid: String!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n": types.EditMarathonHourDataDocument, - "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n uuid\n }\n }\n": types.EditMarathonHourDocument, + "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n": types.EditMarathonHourDocument, "\n query NotificationManager($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationManagerDocument, "\n query NotificationViewer($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationViewerDocument, "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.CreatePersonPageDocument, @@ -104,15 +104,15 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n uuid\n alt\n url\n }\n }\n }\n"): (typeof documents)["\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n uuid\n alt\n url\n }\n }\n }\n"]; +export function graphql(source: "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n"): (typeof documents)["\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment SingleNotificationFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n"): (typeof documents)["\n fragment SingleNotificationFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n"]; +export function graphql(source: "\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n"): (typeof documents)["\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -136,7 +136,7 @@ export function graphql(source: "\n mutation ScheduleNotification($uuid: String /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment TeamNameFragment on TeamResource {\n uuid\n name\n }\n"): (typeof documents)["\n fragment TeamNameFragment on TeamResource {\n uuid\n name\n }\n"]; +export function graphql(source: "\n fragment TeamNameFragment on TeamNode {\n id\n name\n }\n"): (typeof documents)["\n fragment TeamNameFragment on TeamNode {\n id\n name\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -144,7 +144,7 @@ export function graphql(source: "\n mutation PersonCreator($input: CreatePerson /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PersonEditorFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n"): (typeof documents)["\n fragment PersonEditorFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment PersonEditorFragment on PersonNode {\n id\n name\n linkblue\n email\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n fragment PersonEditorFragment on PersonNode {\n id\n name\n linkblue\n email\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -152,19 +152,19 @@ export function graphql(source: "\n mutation PersonEditor($uuid: String!, $inpu /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n uuid\n }\n }\n }\n"): (typeof documents)["\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n uuid\n }\n }\n }\n"]; +export function graphql(source: "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n id\n }\n }\n }\n"): (typeof documents)["\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n id\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n uuid\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n uuid\n name\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n uuid\n name\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n uuid\n name\n }\n }\n }\n"): (typeof documents)["\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n uuid\n name\n }\n }\n }\n"]; +export function graphql(source: "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -172,7 +172,7 @@ export function graphql(source: "\n mutation CreatePersonByLinkBlue(\n $link /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n uuid\n }\n }\n }\n"): (typeof documents)["\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n uuid\n }\n }\n }\n"]; +export function graphql(source: "\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n id\n }\n }\n }\n"): (typeof documents)["\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n id\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -180,11 +180,11 @@ export function graphql(source: "\n mutation CreatePointOpportunity($input: Cre /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation TeamCreator($input: CreateTeamInput!) {\n createTeam(input: $input) {\n ok\n uuid\n }\n }\n"): (typeof documents)["\n mutation TeamCreator($input: CreateTeamInput!) {\n createTeam(input: $input) {\n ok\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n"): (typeof documents)["\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment TeamEditorFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n persistentIdentifier\n type\n }\n"): (typeof documents)["\n fragment TeamEditorFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n persistentIdentifier\n type\n }\n"]; +export function graphql(source: "\n fragment TeamEditorFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n type\n }\n"): (typeof documents)["\n fragment TeamEditorFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n type\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -192,7 +192,7 @@ export function graphql(source: "\n mutation TeamEditor($uuid: String!, $input: /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PeopleTableFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n"): (typeof documents)["\n fragment PeopleTableFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n"]; +export function graphql(source: "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n"): (typeof documents)["\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -204,11 +204,11 @@ export function graphql(source: "\n query TeamsTable(\n $page: Int\n $pag /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment TeamsTableFragment on TeamResource {\n uuid\n type\n name\n legacyStatus\n marathonYear\n totalPoints\n }\n"): (typeof documents)["\n fragment TeamsTableFragment on TeamResource {\n uuid\n type\n name\n legacyStatus\n marathonYear\n totalPoints\n }\n"]; +export function graphql(source: "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n"): (typeof documents)["\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryResource {\n uuid\n deliveryError\n receiptCheckedAt\n sentAt\n }\n"): (typeof documents)["\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryResource {\n uuid\n deliveryError\n receiptCheckedAt\n sentAt\n }\n"]; +export function graphql(source: "\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryNode {\n id\n deliveryError\n receiptCheckedAt\n sentAt\n }\n"): (typeof documents)["\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryNode {\n id\n deliveryError\n receiptCheckedAt\n sentAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -216,7 +216,7 @@ export function graphql(source: "\n query NotificationDeliveriesTableQuery(\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment NotificationsTableFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n"): (typeof documents)["\n fragment NotificationsTableFragment on NotificationResource {\n uuid\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n"]; +export function graphql(source: "\n fragment NotificationsTableFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n"): (typeof documents)["\n fragment NotificationsTableFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -228,7 +228,7 @@ export function graphql(source: "\n mutation DeletePointEntry($uuid: String!) { /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PointEntryTableFragment on PointEntryResource {\n uuid\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n"): (typeof documents)["\n fragment PointEntryTableFragment on PointEntryResource {\n uuid\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n"]; +export function graphql(source: "\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n"): (typeof documents)["\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -236,7 +236,7 @@ export function graphql(source: "\n mutation DeletePerson($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PersonViewerFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n"): (typeof documents)["\n fragment PersonViewerFragment on PersonResource {\n uuid\n name\n linkblue\n email\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n teams {\n position\n team {\n uuid\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -244,11 +244,11 @@ export function graphql(source: "\n mutation DeleteTeam($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment TeamViewerFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n totalPoints\n type\n members {\n person {\n uuid\n name\n linkblue\n }\n }\n captains {\n person {\n uuid\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n fragment TeamViewerFragment on TeamResource {\n uuid\n name\n marathonYear\n legacyStatus\n totalPoints\n type\n members {\n person {\n uuid\n name\n linkblue\n }\n }\n captains {\n person {\n uuid\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n"): (typeof documents)["\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n role {\n dbRole\n committeeRole\n committeeIdentifier\n }\n }\n }\n"]; +export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -256,7 +256,7 @@ export function graphql(source: "\n mutation CommitConfigChanges($changes: [Cre /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ConfigFragment on ConfigurationResource {\n uuid\n key\n value\n validAfter\n validUntil\n createdAt\n }\n"): (typeof documents)["\n fragment ConfigFragment on ConfigurationResource {\n uuid\n key\n value\n validAfter\n validUntil\n createdAt\n }\n"]; +export function graphql(source: "\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n"): (typeof documents)["\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -264,11 +264,11 @@ export function graphql(source: "\n query ConfigQuery {\n allConfigu /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n uuid\n }\n }\n }\n"): (typeof documents)["\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n uuid\n }\n }\n }\n"]; +export function graphql(source: "\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n id\n }\n }\n }\n"): (typeof documents)["\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n id\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventsTableFragment on EventResource {\n uuid\n title\n description\n occurrences {\n uuid\n interval\n fullDay\n }\n summary\n }\n"): (typeof documents)["\n fragment EventsTableFragment on EventResource {\n uuid\n title\n description\n occurrences {\n uuid\n interval\n fullDay\n }\n summary\n }\n"]; +export function graphql(source: "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"): (typeof documents)["\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -280,7 +280,7 @@ export function graphql(source: "\n query EditEventPage($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventEditorFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"): (typeof documents)["\n fragment EventEditorFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n uuid\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"]; +export function graphql(source: "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"): (typeof documents)["\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -292,7 +292,7 @@ export function graphql(source: "\n mutation DeleteEvent($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventViewerFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n"): (typeof documents)["\n fragment EventViewerFragment on EventResource {\n uuid\n title\n summary\n description\n location\n occurrences {\n interval\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n"]; +export function graphql(source: "\n fragment EventViewerFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n"): (typeof documents)["\n fragment EventViewerFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -300,11 +300,11 @@ export function graphql(source: "\n query ViewEventPage($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query FeedPage {\n feed(limit: null) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n"): (typeof documents)["\n query FeedPage {\n feed(limit: null) {\n uuid\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n"]; +export function graphql(source: "\n query FeedPage {\n feed(limit: null) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n"): (typeof documents)["\n query FeedPage {\n feed(limit: null) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n uuid\n }\n }\n"): (typeof documents)["\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -312,11 +312,11 @@ export function graphql(source: "\n mutation DeleteFeedItem($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n uuid\n }\n }\n"): (typeof documents)["\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreateImage($input: CreateImageInput!) {\n createImage(input: $input) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ImagesTableFragment on ImageResource {\n uuid\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n"): (typeof documents)["\n fragment ImagesTableFragment on ImageResource {\n uuid\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n"]; +export function graphql(source: "\n fragment ImagesTableFragment on ImageNode {\n id\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n"): (typeof documents)["\n fragment ImagesTableFragment on ImageNode {\n id\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -324,7 +324,7 @@ export function graphql(source: "\n query ImagesTable(\n $page: Int\n $pa /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n uuid\n }\n }\n "): (typeof documents)["\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n uuid\n }\n }\n "]; +export function graphql(source: "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n id\n }\n }\n "): (typeof documents)["\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n id\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -332,11 +332,11 @@ export function graphql(source: "\n query MarathonOverviewPage {\n nextMarat /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment MarathonTableFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n }\n"): (typeof documents)["\n fragment MarathonTableFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n }\n"]; +export function graphql(source: "\n fragment MarathonTableFragment on MarathonNode {\n id\n year\n startDate\n endDate\n }\n"): (typeof documents)["\n fragment MarathonTableFragment on MarathonNode {\n id\n year\n startDate\n endDate\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n uuid\n }\n }\n "): (typeof documents)["\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n uuid\n }\n }\n "]; +export function graphql(source: "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "): (typeof documents)["\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -344,7 +344,7 @@ export function graphql(source: "\n query GetMarathon($marathonId: String!) /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment MarathonViewerFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n hours {\n uuid\n shownStartingAt\n title\n }\n }\n"): (typeof documents)["\n fragment MarathonViewerFragment on MarathonResource {\n uuid\n year\n startDate\n endDate\n hours {\n uuid\n shownStartingAt\n title\n }\n }\n"]; +export function graphql(source: "\n fragment MarathonViewerFragment on MarathonNode {\n id\n year\n startDate\n endDate\n hours {\n id\n shownStartingAt\n title\n }\n }\n"): (typeof documents)["\n fragment MarathonViewerFragment on MarathonNode {\n id\n year\n startDate\n endDate\n hours {\n id\n shownStartingAt\n title\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -352,7 +352,7 @@ export function graphql(source: "\n query MarathonPage($marathonUuid: String!) /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n uuid\n }\n }\n "): (typeof documents)["\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n uuid\n }\n }\n "]; +export function graphql(source: "\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n id\n }\n }\n "): (typeof documents)["\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n id\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -360,7 +360,7 @@ export function graphql(source: "\n query EditMarathonHourData($marathonHourUui /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n uuid\n }\n }\n"): (typeof documents)["\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"): (typeof documents)["\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 4dd61f05..830487fb 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -1,8 +1,6 @@ /* eslint-disable */ import type { AuthSource } from '../index.js'; import type { DbRole } from '../index.js'; -import type { CommitteeRole } from '../index.js'; -import type { CommitteeIdentifier } from '../index.js'; import type { MembershipPositionType } from '../index.js'; import type { TeamLegacyStatus } from '../index.js'; import type { TeamType } from '../index.js'; @@ -28,10 +26,6 @@ export type Scalars = { DateTimeISO: { input: Date | string; output: Date | string; } /** A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. */ EmailAddress: { input: string; output: string; } - /** Date range custom scalar type (just an ISO 8601 interval) */ - LuxonDateRange: { input: string; output: string; } - /** Luxon DateTime custom scalar type */ - LuxonDateTime: { input: string; output: string; } /** Integers that will have a value of 0 or more. */ NonNegativeInt: { input: number; output: number; } /** Integers that will have a value greater than 0. */ @@ -83,43 +77,33 @@ export type AcknowledgeDeliveryIssueResponse = AbstractGraphQlOkResponse & Graph export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'AddEventImageResponse'; - readonly data: ImageResource; + readonly data: ImageNode; readonly ok: Scalars['Boolean']['output']; }; -export type AuthIdPairResource = { - readonly __typename?: 'AuthIdPairResource'; - readonly source: AuthSource; - readonly value: Scalars['String']['output']; -}; - export { AuthSource }; -export { CommitteeIdentifier }; - -export { CommitteeRole }; - -export type ConfigurationResource = { - readonly __typename?: 'ConfigurationResource'; +export type ConfigurationNode = Node & { + readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; readonly key: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly validAfter?: Maybe; - readonly validUntil?: Maybe; + readonly validAfter?: Maybe; + readonly validUntil?: Maybe; readonly value: Scalars['String']['output']; }; export type CreateConfigurationInput = { readonly key: Scalars['String']['input']; - readonly validAfter?: InputMaybe; - readonly validUntil?: InputMaybe; + readonly validAfter?: InputMaybe; + readonly validUntil?: InputMaybe; readonly value: Scalars['String']['input']; }; export type CreateConfigurationResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateConfigurationResponse'; - readonly data: ConfigurationResource; + readonly data: ConfigurationNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -134,12 +118,12 @@ export type CreateEventInput = { export type CreateEventOccurrenceInput = { readonly fullDay: Scalars['Boolean']['input']; - readonly interval: Scalars['LuxonDateRange']['input']; + readonly interval: IntervalIsoInput; }; export type CreateEventResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateEventResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -170,16 +154,16 @@ export type CreateMarathonInput = { export type CreatePersonInput = { readonly captainOf?: ReadonlyArray; + readonly dbRole?: InputMaybe; readonly email: Scalars['EmailAddress']['input']; readonly linkblue?: InputMaybe; readonly memberOf?: ReadonlyArray; readonly name?: InputMaybe; - readonly role?: InputMaybe; }; export type CreatePersonResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePersonResponse'; - readonly data: PersonResource; + readonly data: PersonNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -194,7 +178,7 @@ export type CreatePointEntryInput = { export type CreatePointEntryResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePointEntryResponse'; - readonly data: PointEntryResource; + readonly data: PointEntryNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -202,13 +186,13 @@ export type CreatePointEntryResponse = AbstractGraphQlCreatedResponse & Abstract export type CreatePointOpportunityInput = { readonly eventUuid?: InputMaybe; readonly name: Scalars['String']['input']; - readonly opportunityDate?: InputMaybe; + readonly opportunityDate?: InputMaybe; readonly type: TeamType; }; export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreatePointOpportunityResponse'; - readonly data: PointOpportunityResource; + readonly data: PointOpportunityNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -223,7 +207,7 @@ export type CreateTeamInput = { export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'CreateTeamResponse'; - readonly data: TeamResource; + readonly data: TeamNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -276,6 +260,23 @@ export type DeleteTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse readonly ok: Scalars['Boolean']['output']; }; +export type DeviceNode = Node & { + readonly __typename?: 'DeviceNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly lastLoggedInUser?: Maybe; + readonly lastLogin?: Maybe; + readonly notificationDeliveries: ReadonlyArray; + readonly updatedAt?: Maybe; +}; + + +export type DeviceNodeNotificationDeliveriesArgs = { + page?: InputMaybe; + pageSize?: InputMaybe; + verifier?: InputMaybe; +}; + export const DeviceResolverAllKeys = { CreatedAt: 'createdAt', ExpoPushToken: 'expoPushToken', @@ -298,7 +299,7 @@ export type DeviceResolverKeyedDateFilterItem = { readonly field: DeviceResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type DeviceResolverKeyedIsNullFilterItem = { @@ -331,28 +332,23 @@ export const DeviceResolverStringFilterKeys = { } as const; export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; -export type DeviceResource = { - readonly __typename?: 'DeviceResource'; +export type EventNode = Node & { + readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; - readonly expoPushToken?: Maybe; - readonly lastLoggedInUser?: Maybe; - readonly lastLogin?: Maybe; - readonly notificationDeliveries: ReadonlyArray; + readonly description?: Maybe; + readonly id: Scalars['ID']['output']; + readonly images: ReadonlyArray; + readonly location?: Maybe; + readonly occurrences: ReadonlyArray; + readonly summary?: Maybe; + readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; - -export type DeviceResourceNotificationDeliveriesArgs = { - page?: InputMaybe; - pageSize?: InputMaybe; - verifier?: InputMaybe; -}; - -export type EventOccurrenceResource = { - readonly __typename?: 'EventOccurrenceResource'; +export type EventOccurrenceNode = { + readonly __typename?: 'EventOccurrenceNode'; readonly fullDay: Scalars['Boolean']['output']; - readonly interval: Scalars['LuxonDateRange']['output']; + readonly interval: IntervalIso; readonly uuid: Scalars['ID']['output']; }; @@ -385,7 +381,7 @@ export type EventResolverKeyedDateFilterItem = { readonly field: EventResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type EventResolverKeyedIsNullFilterItem = { @@ -421,80 +417,73 @@ export const EventResolverStringFilterKeys = { } as const; export type EventResolverStringFilterKeys = typeof EventResolverStringFilterKeys[keyof typeof EventResolverStringFilterKeys]; -export type EventResource = { - readonly __typename?: 'EventResource'; - readonly createdAt?: Maybe; - readonly description?: Maybe; - readonly images: ReadonlyArray; - readonly location?: Maybe; - readonly occurrences: ReadonlyArray; - readonly summary?: Maybe; - readonly title: Scalars['String']['output']; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - -export type FeedResource = { - readonly __typename?: 'FeedResource'; +export type FeedNode = Node & { + readonly __typename?: 'FeedNode'; readonly createdAt?: Maybe; - readonly image?: Maybe; + readonly id: Scalars['ID']['output']; + readonly image?: Maybe; readonly textContent?: Maybe; readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export type GetAllConfigurationsResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetAllConfigurationsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; }; export type GetConfigurationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetConfigurationByUuidResponse'; - readonly data: ConfigurationResource; + readonly data: ConfigurationNode; readonly ok: Scalars['Boolean']['output']; }; export type GetDeviceByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetDeviceByUuidResponse'; - readonly data: DeviceResource; + readonly data: DeviceNode; readonly ok: Scalars['Boolean']['output']; }; export type GetEventByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetEventByUuidResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; }; export type GetImageByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetImageByUuidResponse'; - readonly data: ImageResource; + readonly data: ImageNode; + readonly ok: Scalars['Boolean']['output']; +}; + +export type GetMembershipResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { + readonly __typename?: 'GetMembershipResponse'; + readonly data?: Maybe; readonly ok: Scalars['Boolean']['output']; }; export type GetNotificationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetNotificationByUuidResponse'; - readonly data: NotificationResource; + readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; }; export type GetPeopleResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPeopleResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; }; export type GetPersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPersonResponse'; - readonly data?: Maybe; + readonly data?: Maybe; readonly ok: Scalars['Boolean']['output']; }; export type GetPointEntryByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPointEntryByUuidResponse'; - readonly data: PointEntryResource; + readonly data: PointEntryNode; readonly ok: Scalars['Boolean']['output']; }; @@ -503,6 +492,19 @@ export type GraphQlBaseResponse = { readonly ok: Scalars['Boolean']['output']; }; +export type ImageNode = Node & { + readonly __typename?: 'ImageNode'; + readonly alt?: Maybe; + readonly createdAt?: Maybe; + readonly height: Scalars['Int']['output']; + readonly id: Scalars['ID']['output']; + readonly mimeType: Scalars['String']['output']; + readonly thumbHash?: Maybe; + readonly updatedAt?: Maybe; + readonly url?: Maybe; + readonly width: Scalars['Int']['output']; +}; + export const ImageResolverAllKeys = { Alt: 'alt', CreatedAt: 'createdAt', @@ -525,7 +527,7 @@ export type ImageResolverKeyedDateFilterItem = { readonly field: ImageResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type ImageResolverKeyedIsNullFilterItem = { @@ -574,22 +576,20 @@ export const ImageResolverStringFilterKeys = { } as const; export type ImageResolverStringFilterKeys = typeof ImageResolverStringFilterKeys[keyof typeof ImageResolverStringFilterKeys]; -export type ImageResource = { - readonly __typename?: 'ImageResource'; - readonly alt?: Maybe; - readonly createdAt?: Maybe; - readonly height: Scalars['Int']['output']; - readonly mimeType: Scalars['String']['output']; - readonly thumbHash?: Maybe; - readonly updatedAt?: Maybe; - readonly url?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly width: Scalars['Int']['output']; +export type IntervalIso = { + readonly __typename?: 'IntervalISO'; + readonly end: Scalars['DateTimeISO']['output']; + readonly start: Scalars['DateTimeISO']['output']; +}; + +export type IntervalIsoInput = { + readonly end: Scalars['DateTimeISO']['input']; + readonly start: Scalars['DateTimeISO']['input']; }; export type ListDevicesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListDevicesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -601,7 +601,7 @@ export type ListDevicesResponse = AbstractGraphQlArrayOkResponse & AbstractGraph export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListEventsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -613,7 +613,7 @@ export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListImagesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -625,7 +625,7 @@ export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListMarathonsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListMarathonsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -637,7 +637,7 @@ export type ListMarathonsResponse = AbstractGraphQlArrayOkResponse & AbstractGra export type ListNotificationDeliveriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListNotificationDeliveriesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -649,7 +649,7 @@ export type ListNotificationDeliveriesResponse = AbstractGraphQlArrayOkResponse export type ListNotificationsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListNotificationsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -661,7 +661,7 @@ export type ListNotificationsResponse = AbstractGraphQlArrayOkResponse & Abstrac export type ListPeopleResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPeopleResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -673,7 +673,7 @@ export type ListPeopleResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ export type ListPointEntriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPointEntriesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -685,7 +685,7 @@ export type ListPointEntriesResponse = AbstractGraphQlArrayOkResponse & Abstract export type ListPointOpportunitiesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListPointOpportunitiesResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -697,7 +697,7 @@ export type ListPointOpportunitiesResponse = AbstractGraphQlArrayOkResponse & Ab export type ListTeamsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListTeamsResponse'; - readonly data: ReadonlyArray; + readonly data: ReadonlyArray; readonly ok: Scalars['Boolean']['output']; /** The current page number (1-indexed) */ readonly page: Scalars['PositiveInt']['output']; @@ -710,20 +710,31 @@ export type ListTeamsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQl export type LoginState = { readonly __typename?: 'LoginState'; readonly authSource: AuthSource; + readonly dbRole: DbRole; readonly loggedIn: Scalars['Boolean']['output']; - readonly role: RoleResource; }; -export type MarathonHourResource = { - readonly __typename?: 'MarathonHourResource'; +export type MarathonHourNode = Node & { + readonly __typename?: 'MarathonHourNode'; readonly createdAt?: Maybe; readonly details?: Maybe; readonly durationInfo: Scalars['String']['output']; - readonly mapImages: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly mapImages: ReadonlyArray; readonly shownStartingAt: Scalars['DateTimeISO']['output']; readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; +}; + +export type MarathonNode = Node & { + readonly __typename?: 'MarathonNode'; + readonly createdAt?: Maybe; + readonly endDate?: Maybe; + readonly hours: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly startDate?: Maybe; + readonly updatedAt?: Maybe; + readonly year: Scalars['String']['output']; }; export const MarathonResolverAllKeys = { @@ -750,7 +761,7 @@ export type MarathonResolverKeyedDateFilterItem = { readonly field: MarathonResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type MarathonResolverKeyedIsNullFilterItem = { @@ -760,43 +771,33 @@ export type MarathonResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type MarathonResource = { - readonly __typename?: 'MarathonResource'; +export type MembershipNode = Node & { + readonly __typename?: 'MembershipNode'; readonly createdAt?: Maybe; - readonly endDate: Scalars['DateTimeISO']['output']; - readonly hours: ReadonlyArray; - readonly startDate: Scalars['DateTimeISO']['output']; + readonly id: Scalars['ID']['output']; + readonly person: PersonNode; + readonly position: MembershipPositionType; + readonly team: TeamNode; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; - readonly year: Scalars['String']['output']; }; export { MembershipPositionType }; -export type MembershipResource = { - readonly __typename?: 'MembershipResource'; - readonly createdAt?: Maybe; - readonly person: PersonResource; - readonly position: MembershipPositionType; - readonly team: TeamResource; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export type Mutation = { readonly __typename?: 'Mutation'; readonly abortScheduledNotification: AbortScheduledNotificationResponse; readonly acknowledgeDeliveryIssue: AcknowledgeDeliveryIssueResponse; readonly addExistingImageToEvent: AddEventImageResponse; - readonly addMap: MarathonHourResource; - readonly attachImageToFeedItem: FeedResource; + readonly addMap: MarathonHourNode; + readonly addPersonToTeam: GetMembershipResponse; + readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; readonly createEvent: CreateEventResponse; - readonly createFeedItem: FeedResource; - readonly createImage: ImageResource; - readonly createMarathon: MarathonResource; - readonly createMarathonHour: MarathonHourResource; + readonly createFeedItem: FeedNode; + readonly createImage: ImageNode; + readonly createMarathon: MarathonNode; + readonly createMarathonHour: MarathonHourNode; readonly createPerson: CreatePersonResponse; readonly createPointEntry: CreatePointEntryResponse; readonly createPointOpportunity: CreatePointOpportunityResponse; @@ -815,17 +816,17 @@ export type Mutation = { readonly deleteTeam: DeleteTeamResponse; readonly registerDevice: RegisterDeviceResponse; readonly removeImageFromEvent: RemoveEventImageResponse; - readonly removeImageFromFeedItem: FeedResource; + readonly removeImageFromFeedItem: FeedNode; readonly removeMap: Scalars['Void']['output']; readonly scheduleNotification: ScheduleNotificationResponse; /** Send a notification immediately. */ readonly sendNotification: SendNotificationResponse; readonly setEvent: SetEventResponse; - readonly setFeedItem: FeedResource; - readonly setImageAltText: ImageResource; - readonly setImageUrl: ImageResource; - readonly setMarathon: MarathonResource; - readonly setMarathonHour: MarathonHourResource; + readonly setFeedItem: FeedNode; + readonly setImageAltText: ImageNode; + readonly setImageUrl: ImageNode; + readonly setMarathon: MarathonNode; + readonly setMarathonHour: MarathonHourNode; readonly setPerson: GetPersonResponse; readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; @@ -855,6 +856,12 @@ export type MutationAddMapArgs = { }; +export type MutationAddPersonToTeamArgs = { + personUuid: Scalars['String']['input']; + teamUuid: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -914,6 +921,7 @@ export type MutationCreatePointOpportunityArgs = { export type MutationCreateTeamArgs = { input: CreateTeamInput; + marathon: Scalars['String']['input']; }; @@ -1071,6 +1079,10 @@ export type MutationStageNotificationArgs = { url?: InputMaybe; }; +export type Node = { + readonly id: Scalars['ID']['output']; +}; + export type NotificationAudienceInput = { readonly all?: InputMaybe; readonly memberOfTeamType?: InputMaybe; @@ -1089,6 +1101,22 @@ export type NotificationDeliveryIssueCount = { readonly Unknown: Scalars['Int']['output']; }; +export type NotificationDeliveryNode = Node & { + readonly __typename?: 'NotificationDeliveryNode'; + /** A unique identifier corresponding the group of notifications this was sent to Expo with. */ + readonly chunkUuid?: Maybe; + readonly createdAt?: Maybe; + /** Any error message returned by Expo when sending the notification. */ + readonly deliveryError?: Maybe; + readonly id: Scalars['ID']['output']; + readonly notification: NotificationNode; + /** The time the server received a delivery receipt from the user. */ + readonly receiptCheckedAt?: Maybe; + /** The time the server sent the notification to Expo for delivery. */ + readonly sentAt?: Maybe; + readonly updatedAt?: Maybe; +}; + export const NotificationDeliveryResolverAllKeys = { CreatedAt: 'createdAt', DeliveryError: 'deliveryError', @@ -1113,7 +1141,7 @@ export type NotificationDeliveryResolverKeyedDateFilterItem = { readonly field: NotificationDeliveryResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type NotificationDeliveryResolverKeyedIsNullFilterItem = { @@ -1123,20 +1151,22 @@ export type NotificationDeliveryResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type NotificationDeliveryResource = { - readonly __typename?: 'NotificationDeliveryResource'; - /** A unique identifier corresponding the group of notifications this was sent to Expo with. */ - readonly chunkUuid?: Maybe; +export type NotificationNode = Node & { + readonly __typename?: 'NotificationNode'; + readonly body: Scalars['String']['output']; readonly createdAt?: Maybe; - /** Any error message returned by Expo when sending the notification. */ - readonly deliveryError?: Maybe; - readonly notification: NotificationResource; - /** The time the server received a delivery receipt from the user. */ - readonly receiptCheckedAt?: Maybe; - /** The time the server sent the notification to Expo for delivery. */ - readonly sentAt?: Maybe; + readonly deliveryCount: Scalars['Int']['output']; + readonly deliveryIssue?: Maybe; + readonly deliveryIssueAcknowledgedAt?: Maybe; + readonly deliveryIssueCount: NotificationDeliveryIssueCount; + readonly id: Scalars['ID']['output']; + /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ + readonly sendAt?: Maybe; + /** The time the server started sending the notification. */ + readonly startedSendingAt?: Maybe; + readonly title: Scalars['String']['output']; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; + readonly url?: Maybe; }; export const NotificationResolverAllKeys = { @@ -1165,7 +1195,7 @@ export type NotificationResolverKeyedDateFilterItem = { readonly field: NotificationResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type NotificationResolverKeyedIsNullFilterItem = { @@ -1204,26 +1234,23 @@ export const NotificationResolverStringFilterKeys = { } as const; export type NotificationResolverStringFilterKeys = typeof NotificationResolverStringFilterKeys[keyof typeof NotificationResolverStringFilterKeys]; -export type NotificationResource = { - readonly __typename?: 'NotificationResource'; - readonly body: Scalars['String']['output']; +export { NumericComparator }; + +export type PersonNode = Node & { + readonly __typename?: 'PersonNode'; + /** @deprecated Use teams instead and filter by position */ + readonly captaincies: ReadonlyArray; + readonly committees: ReadonlyArray; readonly createdAt?: Maybe; - readonly deliveryCount: Scalars['Int']['output']; - readonly deliveryIssue?: Maybe; - readonly deliveryIssueAcknowledgedAt?: Maybe; - readonly deliveryIssueCount: NotificationDeliveryIssueCount; - /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ - readonly sendAt?: Maybe; - /** The time the server started sending the notification. */ - readonly startedSendingAt?: Maybe; - readonly title: Scalars['String']['output']; + readonly dbRole: DbRole; + readonly email: Scalars['String']['output']; + readonly id: Scalars['ID']['output']; + readonly linkblue?: Maybe; + readonly name?: Maybe; + readonly teams: ReadonlyArray; readonly updatedAt?: Maybe; - readonly url?: Maybe; - readonly uuid: Scalars['ID']['output']; }; -export { NumericComparator }; - export const PersonResolverAllKeys = { CommitteeName: 'committeeName', CommitteeRole: 'committeeRole', @@ -1273,20 +1300,16 @@ export const PersonResolverStringFilterKeys = { } as const; export type PersonResolverStringFilterKeys = typeof PersonResolverStringFilterKeys[keyof typeof PersonResolverStringFilterKeys]; -export type PersonResource = { - readonly __typename?: 'PersonResource'; - /** @deprecated This is now provided on the AuthIdPair resource. */ - readonly authIds: ReadonlyArray; - /** @deprecated Use teams instead and filter by position */ - readonly captaincies: ReadonlyArray; +export type PointEntryNode = Node & { + readonly __typename?: 'PointEntryNode'; + readonly comment?: Maybe; readonly createdAt?: Maybe; - readonly email: Scalars['String']['output']; - readonly linkblue?: Maybe; - readonly name?: Maybe; - readonly role: RoleResource; - readonly teams: ReadonlyArray; + readonly id: Scalars['ID']['output']; + readonly personFrom?: Maybe; + readonly pointOpportunity?: Maybe; + readonly points: Scalars['Int']['output']; + readonly team: TeamNode; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export const PointEntryResolverAllKeys = { @@ -1308,7 +1331,7 @@ export type PointEntryResolverKeyedDateFilterItem = { readonly field: PointEntryResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type PointEntryResolverKeyedIsNullFilterItem = { @@ -1318,16 +1341,15 @@ export type PointEntryResolverKeyedIsNullFilterItem = { readonly negate?: InputMaybe; }; -export type PointEntryResource = { - readonly __typename?: 'PointEntryResource'; - readonly comment?: Maybe; +export type PointOpportunityNode = Node & { + readonly __typename?: 'PointOpportunityNode'; readonly createdAt?: Maybe; - readonly personFrom?: Maybe; - readonly pointOpportunity?: Maybe; - readonly points: Scalars['Int']['output']; - readonly team: TeamResource; + readonly event?: Maybe; + readonly id: Scalars['ID']['output']; + readonly name: Scalars['String']['output']; + readonly opportunityDate?: Maybe; + readonly type: TeamType; readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; }; export const PointOpportunityResolverAllKeys = { @@ -1353,7 +1375,7 @@ export type PointOpportunityResolverKeyedDateFilterItem = { readonly field: PointOpportunityResolverDateFilterKeys; /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ readonly negate?: InputMaybe; - readonly value: Scalars['LuxonDateTime']['input']; + readonly value: Scalars['DateTimeISO']['input']; }; export type PointOpportunityResolverKeyedIsNullFilterItem = { @@ -1391,38 +1413,27 @@ export const PointOpportunityResolverStringFilterKeys = { } as const; export type PointOpportunityResolverStringFilterKeys = typeof PointOpportunityResolverStringFilterKeys[keyof typeof PointOpportunityResolverStringFilterKeys]; -export type PointOpportunityResource = { - readonly __typename?: 'PointOpportunityResource'; - readonly createdAt?: Maybe; - readonly event?: Maybe; - readonly name: Scalars['String']['output']; - readonly opportunityDate?: Maybe; - readonly type: TeamType; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export type Query = { readonly __typename?: 'Query'; readonly activeConfiguration: GetConfigurationByUuidResponse; readonly allConfigurations: GetAllConfigurationsResponse; - readonly currentMarathon?: Maybe; - readonly currentMarathonHour?: Maybe; + readonly currentMarathon?: Maybe; + readonly currentMarathonHour?: Maybe; readonly device: GetDeviceByUuidResponse; readonly devices: ListDevicesResponse; readonly event: GetEventByUuidResponse; readonly events: ListEventsResponse; - readonly feed: ReadonlyArray; + readonly feed: ReadonlyArray; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; readonly listPeople: ListPeopleResponse; readonly loginState: LoginState; - readonly marathon: MarathonResource; - readonly marathonForYear: MarathonResource; - readonly marathonHour: MarathonHourResource; + readonly marathon: MarathonNode; + readonly marathonForYear: MarathonNode; + readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; - readonly nextMarathon?: Maybe; + readonly nextMarathon?: Maybe; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -1689,7 +1700,7 @@ export type RegisterDeviceInput = { export type RegisterDeviceResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'RegisterDeviceResponse'; - readonly data: DeviceResource; + readonly data: DeviceNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1699,19 +1710,6 @@ export type RemoveEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRe readonly ok: Scalars['Boolean']['output']; }; -export type RoleResource = { - readonly __typename?: 'RoleResource'; - readonly committeeIdentifier?: Maybe; - readonly committeeRole?: Maybe; - readonly dbRole: DbRole; -}; - -export type RoleResourceInput = { - readonly committeeIdentifier?: InputMaybe; - readonly committeeRole?: InputMaybe; - readonly dbRole?: DbRole; -}; - export type ScheduleNotificationResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'ScheduleNotificationResponse'; readonly data: Scalars['Boolean']['output']; @@ -1734,14 +1732,14 @@ export type SetEventInput = { export type SetEventOccurrenceInput = { readonly fullDay: Scalars['Boolean']['input']; - readonly interval: Scalars['LuxonDateRange']['input']; + readonly interval: IntervalIsoInput; /** If updating an existing occurrence, the UUID of the occurrence to update */ readonly uuid?: InputMaybe; }; export type SetEventResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SetEventResponse'; - readonly data: EventResource; + readonly data: EventNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1765,17 +1763,17 @@ export type SetMarathonInput = { export type SetPersonInput = { readonly captainOf?: InputMaybe>; + readonly dbRole?: InputMaybe; readonly email?: InputMaybe; readonly linkblue?: InputMaybe; readonly memberOf?: InputMaybe>; readonly name?: InputMaybe; - readonly role?: InputMaybe; }; export type SetPointOpportunityInput = { readonly eventUuid?: InputMaybe; readonly name?: InputMaybe; - readonly opportunityDate?: InputMaybe; + readonly opportunityDate?: InputMaybe; readonly type?: InputMaybe; }; @@ -1789,13 +1787,13 @@ export type SetTeamInput = { export type SinglePointOpportunityResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SinglePointOpportunityResponse'; - readonly data: PointOpportunityResource; + readonly data: PointOpportunityNode; readonly ok: Scalars['Boolean']['output']; }; export type SingleTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'SingleTeamResponse'; - readonly data: TeamResource; + readonly data: TeamNode; readonly ok: Scalars['Boolean']['output']; }; @@ -1803,7 +1801,7 @@ export { SortDirection }; export type StageNotificationResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'StageNotificationResponse'; - readonly data: NotificationResource; + readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; readonly uuid: Scalars['String']['output']; }; @@ -1812,6 +1810,22 @@ export { StringComparator }; export { TeamLegacyStatus }; +export type TeamNode = Node & { + readonly __typename?: 'TeamNode'; + /** @deprecated Just query the members field and filter by role */ + readonly captains: ReadonlyArray; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly legacyStatus: TeamLegacyStatus; + readonly marathon: MarathonNode; + readonly members: ReadonlyArray; + readonly name: Scalars['String']['output']; + readonly pointEntries: ReadonlyArray; + readonly totalPoints: Scalars['Int']['output']; + readonly type: TeamType; + readonly updatedAt?: Maybe; +}; + export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', MarathonYear: 'marathonYear', @@ -1857,23 +1871,6 @@ export const TeamResolverStringFilterKeys = { } as const; export type TeamResolverStringFilterKeys = typeof TeamResolverStringFilterKeys[keyof typeof TeamResolverStringFilterKeys]; -export type TeamResource = { - readonly __typename?: 'TeamResource'; - /** @deprecated Just query the members field and filter by role */ - readonly captains: ReadonlyArray; - readonly createdAt?: Maybe; - readonly legacyStatus: TeamLegacyStatus; - readonly marathonYear: Scalars['String']['output']; - readonly members: ReadonlyArray; - readonly name: Scalars['String']['output']; - readonly persistentIdentifier?: Maybe; - readonly pointEntries: ReadonlyArray; - readonly totalPoints: Scalars['Int']['output']; - readonly type: TeamType; - readonly updatedAt?: Maybe; - readonly uuid: Scalars['ID']['output']; -}; - export { TeamType }; export type ImagePickerQueryVariables = Exact<{ @@ -1881,16 +1878,16 @@ export type ImagePickerQueryVariables = Exact<{ }>; -export type ImagePickerQuery = { readonly __typename?: 'Query', readonly images: { readonly __typename?: 'ListImagesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'ImageResource', readonly uuid: string, readonly alt?: string | null, readonly url?: URL | string | null }> } }; +export type ImagePickerQuery = { readonly __typename?: 'Query', readonly images: { readonly __typename?: 'ListImagesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly id: string, readonly alt?: string | null, readonly url?: URL | string | null }> } }; export type PersonSearchQueryVariables = Exact<{ search: Scalars['String']['input']; }>; -export type PersonSearchQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null }> }, readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; +export type PersonSearchQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null }> }, readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; -export type SingleNotificationFragmentFragment = { readonly __typename?: 'NotificationResource', readonly uuid: string, readonly title: string, readonly body: string, readonly deliveryIssue?: string | null, readonly deliveryIssueAcknowledgedAt?: Date | string | null, readonly sendAt?: Date | string | null, readonly startedSendingAt?: Date | string | null, readonly createdAt?: Date | string | null, readonly deliveryCount: number, readonly deliveryIssueCount: { readonly __typename?: 'NotificationDeliveryIssueCount', readonly DeviceNotRegistered: number, readonly InvalidCredentials: number, readonly MessageRateExceeded: number, readonly MessageTooBig: number, readonly MismatchSenderId: number, readonly Unknown: number } } & { ' $fragmentName'?: 'SingleNotificationFragmentFragment' }; +export type SingleNotificationFragmentFragment = { readonly __typename?: 'NotificationNode', readonly id: string, readonly title: string, readonly body: string, readonly deliveryIssue?: string | null, readonly deliveryIssueAcknowledgedAt?: Date | string | null, readonly sendAt?: Date | string | null, readonly startedSendingAt?: Date | string | null, readonly createdAt?: Date | string | null, readonly deliveryCount: number, readonly deliveryIssueCount: { readonly __typename?: 'NotificationDeliveryIssueCount', readonly DeviceNotRegistered: number, readonly InvalidCredentials: number, readonly MessageRateExceeded: number, readonly MessageTooBig: number, readonly MismatchSenderId: number, readonly Unknown: number } } & { ' $fragmentName'?: 'SingleNotificationFragmentFragment' }; export type CreateNotificationMutationVariables = Exact<{ title: Scalars['String']['input']; @@ -1932,7 +1929,7 @@ export type ScheduleNotificationMutationVariables = Exact<{ export type ScheduleNotificationMutation = { readonly __typename?: 'Mutation', readonly scheduleNotification: { readonly __typename?: 'ScheduleNotificationResponse', readonly ok: boolean } }; -export type TeamNameFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string } & { ' $fragmentName'?: 'TeamNameFragmentFragment' }; +export type TeamNameFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } & { ' $fragmentName'?: 'TeamNameFragmentFragment' }; export type PersonCreatorMutationVariables = Exact<{ input: CreatePersonInput; @@ -1941,7 +1938,7 @@ export type PersonCreatorMutationVariables = Exact<{ export type PersonCreatorMutation = { readonly __typename?: 'Mutation', readonly createPerson: { readonly __typename?: 'CreatePersonResponse', readonly ok: boolean, readonly uuid: string } }; -export type PersonEditorFragmentFragment = { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly role: { readonly __typename?: 'RoleResource', readonly committeeRole?: CommitteeRole | null, readonly committeeIdentifier?: CommitteeIdentifier | null }, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonEditorFragmentFragment' }; +export type PersonEditorFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonEditorFragmentFragment' }; export type PersonEditorMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -1956,28 +1953,28 @@ export type CreatePointEntryMutationVariables = Exact<{ }>; -export type CreatePointEntryMutation = { readonly __typename?: 'Mutation', readonly createPointEntry: { readonly __typename?: 'CreatePointEntryResponse', readonly data: { readonly __typename?: 'PointEntryResource', readonly uuid: string } } }; +export type CreatePointEntryMutation = { readonly __typename?: 'Mutation', readonly createPointEntry: { readonly __typename?: 'CreatePointEntryResponse', readonly data: { readonly __typename?: 'PointEntryNode', readonly id: string } } }; export type GetPersonByUuidQueryVariables = Exact<{ uuid: Scalars['String']['input']; }>; -export type GetPersonByUuidQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; +export type GetPersonByUuidQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; export type GetPersonByLinkBlueQueryVariables = Exact<{ linkBlue: Scalars['String']['input']; }>; -export type GetPersonByLinkBlueQuery = { readonly __typename?: 'Query', readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null } | null } }; +export type GetPersonByLinkBlueQuery = { readonly __typename?: 'Query', readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null } | null } }; export type SearchPersonByNameQueryVariables = Exact<{ name: Scalars['String']['input']; }>; -export type SearchPersonByNameQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null }> } }; +export type SearchPersonByNameQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null }> } }; export type CreatePersonByLinkBlueMutationVariables = Exact<{ linkBlue: Scalars['String']['input']; @@ -1993,7 +1990,7 @@ export type PointEntryOpportunityLookupQueryVariables = Exact<{ }>; -export type PointEntryOpportunityLookupQuery = { readonly __typename?: 'Query', readonly pointOpportunities: { readonly __typename?: 'ListPointOpportunitiesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PointOpportunityResource', readonly name: string, readonly uuid: string }> } }; +export type PointEntryOpportunityLookupQuery = { readonly __typename?: 'Query', readonly pointOpportunities: { readonly __typename?: 'ListPointOpportunitiesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PointOpportunityNode', readonly name: string, readonly id: string }> } }; export type CreatePointOpportunityMutationVariables = Exact<{ input: CreatePointOpportunityInput; @@ -2004,12 +2001,13 @@ export type CreatePointOpportunityMutation = { readonly __typename?: 'Mutation', export type TeamCreatorMutationVariables = Exact<{ input: CreateTeamInput; + marathonUuid: Scalars['String']['input']; }>; export type TeamCreatorMutation = { readonly __typename?: 'Mutation', readonly createTeam: { readonly __typename?: 'CreateTeamResponse', readonly ok: boolean, readonly uuid: string } }; -export type TeamEditorFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string, readonly marathonYear: string, readonly legacyStatus: TeamLegacyStatus, readonly persistentIdentifier?: string | null, readonly type: TeamType } & { ' $fragmentName'?: 'TeamEditorFragmentFragment' }; +export type TeamEditorFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType, readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string } } & { ' $fragmentName'?: 'TeamEditorFragmentFragment' }; export type TeamEditorMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2019,7 +2017,7 @@ export type TeamEditorMutationVariables = Exact<{ export type TeamEditorMutation = { readonly __typename?: 'Mutation', readonly setTeam: { readonly __typename?: 'SingleTeamResponse', readonly ok: boolean } }; -export type PeopleTableFragmentFragment = { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly role: { readonly __typename?: 'RoleResource', readonly dbRole: DbRole, readonly committeeRole?: CommitteeRole | null, readonly committeeIdentifier?: CommitteeIdentifier | null } } & { ' $fragmentName'?: 'PeopleTableFragmentFragment' }; +export type PeopleTableFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole } & { ' $fragmentName'?: 'PeopleTableFragmentFragment' }; export type PeopleTableQueryVariables = Exact<{ page?: InputMaybe; @@ -2033,7 +2031,7 @@ export type PeopleTableQueryVariables = Exact<{ export type PeopleTableQuery = { readonly __typename?: 'Query', readonly listPeople: { readonly __typename?: 'ListPeopleResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'PersonResource' } + { readonly __typename?: 'PersonNode' } & { ' $fragmentRefs'?: { 'PeopleTableFragmentFragment': PeopleTableFragmentFragment } } )> } }; @@ -2049,13 +2047,13 @@ export type TeamsTableQueryVariables = Exact<{ export type TeamsTableQuery = { readonly __typename?: 'Query', readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'TeamResource' } + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'TeamsTableFragmentFragment': TeamsTableFragmentFragment } } )> } }; -export type TeamsTableFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly type: TeamType, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly marathonYear: string, readonly totalPoints: number } & { ' $fragmentName'?: 'TeamsTableFragmentFragment' }; +export type TeamsTableFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly type: TeamType, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly totalPoints: number, readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string } } & { ' $fragmentName'?: 'TeamsTableFragmentFragment' }; -export type NotificationDeliveriesTableFragmentFragment = { readonly __typename?: 'NotificationDeliveryResource', readonly uuid: string, readonly deliveryError?: string | null, readonly receiptCheckedAt?: Date | string | null, readonly sentAt?: Date | string | null } & { ' $fragmentName'?: 'NotificationDeliveriesTableFragmentFragment' }; +export type NotificationDeliveriesTableFragmentFragment = { readonly __typename?: 'NotificationDeliveryNode', readonly id: string, readonly deliveryError?: string | null, readonly receiptCheckedAt?: Date | string | null, readonly sentAt?: Date | string | null } & { ' $fragmentName'?: 'NotificationDeliveriesTableFragmentFragment' }; export type NotificationDeliveriesTableQueryQueryVariables = Exact<{ notificationId: Scalars['String']['input']; @@ -2069,11 +2067,11 @@ export type NotificationDeliveriesTableQueryQueryVariables = Exact<{ export type NotificationDeliveriesTableQueryQuery = { readonly __typename?: 'Query', readonly notificationDeliveries: { readonly __typename?: 'ListNotificationDeliveriesResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'NotificationDeliveryResource' } + { readonly __typename?: 'NotificationDeliveryNode' } & { ' $fragmentRefs'?: { 'NotificationDeliveriesTableFragmentFragment': NotificationDeliveriesTableFragmentFragment } } )> } }; -export type NotificationsTableFragmentFragment = { readonly __typename?: 'NotificationResource', readonly uuid: string, readonly title: string, readonly body: string, readonly deliveryIssue?: string | null, readonly deliveryIssueAcknowledgedAt?: Date | string | null, readonly sendAt?: Date | string | null, readonly startedSendingAt?: Date | string | null } & { ' $fragmentName'?: 'NotificationsTableFragmentFragment' }; +export type NotificationsTableFragmentFragment = { readonly __typename?: 'NotificationNode', readonly id: string, readonly title: string, readonly body: string, readonly deliveryIssue?: string | null, readonly deliveryIssueAcknowledgedAt?: Date | string | null, readonly sendAt?: Date | string | null, readonly startedSendingAt?: Date | string | null } & { ' $fragmentName'?: 'NotificationsTableFragmentFragment' }; export type NotificationsTableQueryQueryVariables = Exact<{ page?: InputMaybe; @@ -2088,7 +2086,7 @@ export type NotificationsTableQueryQueryVariables = Exact<{ export type NotificationsTableQueryQuery = { readonly __typename?: 'Query', readonly notifications: { readonly __typename?: 'ListNotificationsResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'NotificationResource' } + { readonly __typename?: 'NotificationNode' } & { ' $fragmentRefs'?: { 'NotificationsTableFragmentFragment': NotificationsTableFragmentFragment } } )> } }; @@ -2099,7 +2097,7 @@ export type DeletePointEntryMutationVariables = Exact<{ export type DeletePointEntryMutation = { readonly __typename?: 'Mutation', readonly deletePointEntry: { readonly __typename?: 'DeletePointEntryResponse', readonly ok: boolean } }; -export type PointEntryTableFragmentFragment = { readonly __typename?: 'PointEntryResource', readonly uuid: string, readonly points: number, readonly comment?: string | null, readonly personFrom?: { readonly __typename?: 'PersonResource', readonly name?: string | null, readonly linkblue?: string | null } | null, readonly pointOpportunity?: { readonly __typename?: 'PointOpportunityResource', readonly name: string, readonly opportunityDate?: string | null } | null } & { ' $fragmentName'?: 'PointEntryTableFragmentFragment' }; +export type PointEntryTableFragmentFragment = { readonly __typename?: 'PointEntryNode', readonly id: string, readonly points: number, readonly comment?: string | null, readonly personFrom?: { readonly __typename?: 'PersonNode', readonly name?: string | null, readonly linkblue?: string | null } | null, readonly pointOpportunity?: { readonly __typename?: 'PointOpportunityNode', readonly name: string, readonly opportunityDate?: Date | string | null } | null } & { ' $fragmentName'?: 'PointEntryTableFragmentFragment' }; export type DeletePersonMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2108,7 +2106,7 @@ export type DeletePersonMutationVariables = Exact<{ export type DeletePersonMutation = { readonly __typename?: 'Mutation', readonly deletePerson: { readonly __typename?: 'DeletePersonResponse', readonly ok: boolean } }; -export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly role: { readonly __typename?: 'RoleResource', readonly dbRole: DbRole, readonly committeeRole?: CommitteeRole | null, readonly committeeIdentifier?: CommitteeIdentifier | null }, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; +export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; export type DeleteTeamMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2117,12 +2115,12 @@ export type DeleteTeamMutationVariables = Exact<{ export type DeleteTeamMutation = { readonly __typename?: 'Mutation', readonly deleteTeam: { readonly __typename?: 'DeleteTeamResponse', readonly ok: boolean } }; -export type TeamViewerFragmentFragment = { readonly __typename?: 'TeamResource', readonly uuid: string, readonly name: string, readonly marathonYear: string, readonly legacyStatus: TeamLegacyStatus, readonly totalPoints: number, readonly type: TeamType, readonly members: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly person: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null } }>, readonly captains: ReadonlyArray<{ readonly __typename?: 'MembershipResource', readonly person: { readonly __typename?: 'PersonResource', readonly uuid: string, readonly name?: string | null, readonly linkblue?: string | null } }> } & { ' $fragmentName'?: 'TeamViewerFragmentFragment' }; +export type TeamViewerFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly totalPoints: number, readonly type: TeamType, readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string }, readonly members: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly person: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } }> } & { ' $fragmentName'?: 'TeamViewerFragmentFragment' }; export type LoginStateQueryVariables = Exact<{ [key: string]: never; }>; -export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly role: { readonly __typename?: 'RoleResource', readonly dbRole: DbRole, readonly committeeRole?: CommitteeRole | null, readonly committeeIdentifier?: CommitteeIdentifier | null } } }; +export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly dbRole: DbRole } }; export type CommitConfigChangesMutationVariables = Exact<{ changes: ReadonlyArray | CreateConfigurationInput; @@ -2131,13 +2129,13 @@ export type CommitConfigChangesMutationVariables = Exact<{ export type CommitConfigChangesMutation = { readonly __typename?: 'Mutation', readonly createConfigurations: { readonly __typename?: 'CreateConfigurationResponse', readonly ok: boolean } }; -export type ConfigFragmentFragment = { readonly __typename?: 'ConfigurationResource', readonly uuid: string, readonly key: string, readonly value: string, readonly validAfter?: string | null, readonly validUntil?: string | null, readonly createdAt?: Date | string | null } & { ' $fragmentName'?: 'ConfigFragmentFragment' }; +export type ConfigFragmentFragment = { readonly __typename?: 'ConfigurationNode', readonly id: string, readonly key: string, readonly value: string, readonly validAfter?: Date | string | null, readonly validUntil?: Date | string | null, readonly createdAt?: Date | string | null } & { ' $fragmentName'?: 'ConfigFragmentFragment' }; export type ConfigQueryQueryVariables = Exact<{ [key: string]: never; }>; export type ConfigQueryQuery = { readonly __typename?: 'Query', readonly allConfigurations: { readonly __typename?: 'GetAllConfigurationsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'ConfigurationResource' } + { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'ConfigFragmentFragment': ConfigFragmentFragment } } )> } }; @@ -2146,9 +2144,9 @@ export type CreateEventMutationVariables = Exact<{ }>; -export type CreateEventMutation = { readonly __typename?: 'Mutation', readonly createEvent: { readonly __typename?: 'CreateEventResponse', readonly data: { readonly __typename?: 'EventResource', readonly uuid: string } } }; +export type CreateEventMutation = { readonly __typename?: 'Mutation', readonly createEvent: { readonly __typename?: 'CreateEventResponse', readonly data: { readonly __typename?: 'EventNode', readonly id: string } } }; -export type EventsTableFragmentFragment = { readonly __typename?: 'EventResource', readonly uuid: string, readonly title: string, readonly description?: string | null, readonly summary?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceResource', readonly uuid: string, readonly interval: string, readonly fullDay: boolean }> } & { ' $fragmentName'?: 'EventsTableFragmentFragment' }; +export type EventsTableFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly description?: string | null, readonly summary?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }> } & { ' $fragmentName'?: 'EventsTableFragmentFragment' }; export type EventsTableQueryVariables = Exact<{ page?: InputMaybe; @@ -2163,7 +2161,7 @@ export type EventsTableQueryVariables = Exact<{ export type EventsTableQuery = { readonly __typename?: 'Query', readonly events: { readonly __typename?: 'ListEventsResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'EventResource' } + { readonly __typename?: 'EventNode' } & { ' $fragmentRefs'?: { 'EventsTableFragmentFragment': EventsTableFragmentFragment } } )> } }; @@ -2173,11 +2171,11 @@ export type EditEventPageQueryVariables = Exact<{ export type EditEventPageQuery = { readonly __typename?: 'Query', readonly event: { readonly __typename?: 'GetEventByUuidResponse', readonly data: ( - { readonly __typename?: 'EventResource' } + { readonly __typename?: 'EventNode' } & { ' $fragmentRefs'?: { 'EventEditorFragmentFragment': EventEditorFragmentFragment } } ) } }; -export type EventEditorFragmentFragment = { readonly __typename?: 'EventResource', readonly uuid: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceResource', readonly uuid: string, readonly interval: string, readonly fullDay: boolean }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageResource', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventEditorFragmentFragment' }; +export type EventEditorFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventEditorFragmentFragment' }; export type SaveEventMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2186,7 +2184,7 @@ export type SaveEventMutationVariables = Exact<{ export type SaveEventMutation = { readonly __typename?: 'Mutation', readonly setEvent: { readonly __typename?: 'SetEventResponse', readonly data: ( - { readonly __typename?: 'EventResource' } + { readonly __typename?: 'EventNode' } & { ' $fragmentRefs'?: { 'EventEditorFragmentFragment': EventEditorFragmentFragment } } ) } }; @@ -2197,7 +2195,7 @@ export type DeleteEventMutationVariables = Exact<{ export type DeleteEventMutation = { readonly __typename?: 'Mutation', readonly deleteEvent: { readonly __typename?: 'DeleteEventResponse', readonly ok: boolean } }; -export type EventViewerFragmentFragment = { readonly __typename?: 'EventResource', readonly uuid: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly createdAt?: Date | string | null, readonly updatedAt?: Date | string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceResource', readonly interval: string, readonly fullDay: boolean }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageResource', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventViewerFragmentFragment' }; +export type EventViewerFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly createdAt?: Date | string | null, readonly updatedAt?: Date | string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventViewerFragmentFragment' }; export type ViewEventPageQueryVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2205,21 +2203,21 @@ export type ViewEventPageQueryVariables = Exact<{ export type ViewEventPageQuery = { readonly __typename?: 'Query', readonly event: { readonly __typename?: 'GetEventByUuidResponse', readonly data: ( - { readonly __typename?: 'EventResource' } + { readonly __typename?: 'EventNode' } & { ' $fragmentRefs'?: { 'EventViewerFragmentFragment': EventViewerFragmentFragment } } ) } }; export type FeedPageQueryVariables = Exact<{ [key: string]: never; }>; -export type FeedPageQuery = { readonly __typename?: 'Query', readonly feed: ReadonlyArray<{ readonly __typename?: 'FeedResource', readonly uuid: string, readonly title: string, readonly createdAt?: Date | string | null, readonly textContent?: string | null, readonly image?: { readonly __typename?: 'ImageResource', readonly url?: URL | string | null, readonly alt?: string | null } | null }> }; +export type FeedPageQuery = { readonly __typename?: 'Query', readonly feed: ReadonlyArray<{ readonly __typename?: 'FeedNode', readonly id: string, readonly title: string, readonly createdAt?: Date | string | null, readonly textContent?: string | null, readonly image?: { readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly alt?: string | null } | null }> }; export type CreateFeedItemMutationVariables = Exact<{ input: CreateFeedInput; }>; -export type CreateFeedItemMutation = { readonly __typename?: 'Mutation', readonly createFeedItem: { readonly __typename?: 'FeedResource', readonly uuid: string } }; +export type CreateFeedItemMutation = { readonly __typename?: 'Mutation', readonly createFeedItem: { readonly __typename?: 'FeedNode', readonly id: string } }; export type DeleteFeedItemMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2233,9 +2231,9 @@ export type CreateImageMutationVariables = Exact<{ }>; -export type CreateImageMutation = { readonly __typename?: 'Mutation', readonly createImage: { readonly __typename?: 'ImageResource', readonly uuid: string } }; +export type CreateImageMutation = { readonly __typename?: 'Mutation', readonly createImage: { readonly __typename?: 'ImageNode', readonly id: string } }; -export type ImagesTableFragmentFragment = { readonly __typename?: 'ImageResource', readonly uuid: string, readonly url?: URL | string | null, readonly thumbHash?: string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string, readonly createdAt?: Date | string | null } & { ' $fragmentName'?: 'ImagesTableFragmentFragment' }; +export type ImagesTableFragmentFragment = { readonly __typename?: 'ImageNode', readonly id: string, readonly url?: URL | string | null, readonly thumbHash?: string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string, readonly createdAt?: Date | string | null } & { ' $fragmentName'?: 'ImagesTableFragmentFragment' }; export type ImagesTableQueryVariables = Exact<{ page?: InputMaybe; @@ -2251,7 +2249,7 @@ export type ImagesTableQueryVariables = Exact<{ export type ImagesTableQuery = { readonly __typename?: 'Query', readonly images: { readonly __typename?: 'ListImagesResponse', readonly page: number, readonly pageSize: number, readonly total: number, readonly data: ReadonlyArray<( - { readonly __typename?: 'ImageResource' } + { readonly __typename?: 'ImageNode' } & { ' $fragmentRefs'?: { 'ImagesTableFragmentFragment': ImagesTableFragmentFragment } } )> } }; @@ -2260,20 +2258,20 @@ export type CreateMarathonMutationVariables = Exact<{ }>; -export type CreateMarathonMutation = { readonly __typename?: 'Mutation', readonly createMarathon: { readonly __typename?: 'MarathonResource', readonly uuid: string } }; +export type CreateMarathonMutation = { readonly __typename?: 'Mutation', readonly createMarathon: { readonly __typename?: 'MarathonNode', readonly id: string } }; export type MarathonOverviewPageQueryVariables = Exact<{ [key: string]: never; }>; export type MarathonOverviewPageQuery = { readonly __typename?: 'Query', readonly nextMarathon?: ( - { readonly __typename?: 'MarathonResource' } + { readonly __typename?: 'MarathonNode' } & { ' $fragmentRefs'?: { 'MarathonViewerFragmentFragment': MarathonViewerFragmentFragment } } ) | null, readonly marathons: { readonly __typename?: 'ListMarathonsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'MarathonResource' } + { readonly __typename?: 'MarathonNode' } & { ' $fragmentRefs'?: { 'MarathonTableFragmentFragment': MarathonTableFragmentFragment } } )> } }; -export type MarathonTableFragmentFragment = { readonly __typename?: 'MarathonResource', readonly uuid: string, readonly year: string, readonly startDate: Date | string, readonly endDate: Date | string } & { ' $fragmentName'?: 'MarathonTableFragmentFragment' }; +export type MarathonTableFragmentFragment = { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } & { ' $fragmentName'?: 'MarathonTableFragmentFragment' }; export type EditMarathonMutationVariables = Exact<{ input: SetMarathonInput; @@ -2281,16 +2279,16 @@ export type EditMarathonMutationVariables = Exact<{ }>; -export type EditMarathonMutation = { readonly __typename?: 'Mutation', readonly setMarathon: { readonly __typename?: 'MarathonResource', readonly uuid: string } }; +export type EditMarathonMutation = { readonly __typename?: 'Mutation', readonly setMarathon: { readonly __typename?: 'MarathonNode', readonly id: string } }; export type GetMarathonQueryVariables = Exact<{ marathonId: Scalars['String']['input']; }>; -export type GetMarathonQuery = { readonly __typename?: 'Query', readonly marathon: { readonly __typename?: 'MarathonResource', readonly year: string, readonly startDate: Date | string, readonly endDate: Date | string } }; +export type GetMarathonQuery = { readonly __typename?: 'Query', readonly marathon: { readonly __typename?: 'MarathonNode', readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } }; -export type MarathonViewerFragmentFragment = { readonly __typename?: 'MarathonResource', readonly uuid: string, readonly year: string, readonly startDate: Date | string, readonly endDate: Date | string, readonly hours: ReadonlyArray<{ readonly __typename?: 'MarathonHourResource', readonly uuid: string, readonly shownStartingAt: Date | string, readonly title: string }> } & { ' $fragmentName'?: 'MarathonViewerFragmentFragment' }; +export type MarathonViewerFragmentFragment = { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null, readonly hours: ReadonlyArray<{ readonly __typename?: 'MarathonHourNode', readonly id: string, readonly shownStartingAt: Date | string, readonly title: string }> } & { ' $fragmentName'?: 'MarathonViewerFragmentFragment' }; export type MarathonPageQueryVariables = Exact<{ marathonUuid: Scalars['String']['input']; @@ -2298,7 +2296,7 @@ export type MarathonPageQueryVariables = Exact<{ export type MarathonPageQuery = { readonly __typename?: 'Query', readonly marathon: ( - { readonly __typename?: 'MarathonResource' } + { readonly __typename?: 'MarathonNode' } & { ' $fragmentRefs'?: { 'MarathonViewerFragmentFragment': MarathonViewerFragmentFragment } } ) }; @@ -2308,14 +2306,14 @@ export type AddMarathonHourMutationVariables = Exact<{ }>; -export type AddMarathonHourMutation = { readonly __typename?: 'Mutation', readonly createMarathonHour: { readonly __typename?: 'MarathonHourResource', readonly uuid: string } }; +export type AddMarathonHourMutation = { readonly __typename?: 'Mutation', readonly createMarathonHour: { readonly __typename?: 'MarathonHourNode', readonly id: string } }; export type EditMarathonHourDataQueryVariables = Exact<{ marathonHourUuid: Scalars['String']['input']; }>; -export type EditMarathonHourDataQuery = { readonly __typename?: 'Query', readonly marathonHour: { readonly __typename?: 'MarathonHourResource', readonly details?: string | null, readonly durationInfo: string, readonly shownStartingAt: Date | string, readonly title: string } }; +export type EditMarathonHourDataQuery = { readonly __typename?: 'Query', readonly marathonHour: { readonly __typename?: 'MarathonHourNode', readonly details?: string | null, readonly durationInfo: string, readonly shownStartingAt: Date | string, readonly title: string } }; export type EditMarathonHourMutationVariables = Exact<{ input: SetMarathonHourInput; @@ -2323,7 +2321,7 @@ export type EditMarathonHourMutationVariables = Exact<{ }>; -export type EditMarathonHourMutation = { readonly __typename?: 'Mutation', readonly setMarathonHour: { readonly __typename?: 'MarathonHourResource', readonly uuid: string } }; +export type EditMarathonHourMutation = { readonly __typename?: 'Mutation', readonly setMarathonHour: { readonly __typename?: 'MarathonHourNode', readonly id: string } }; export type NotificationManagerQueryVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2331,7 +2329,7 @@ export type NotificationManagerQueryVariables = Exact<{ export type NotificationManagerQuery = { readonly __typename?: 'Query', readonly notification: { readonly __typename?: 'GetNotificationByUuidResponse', readonly data: ( - { readonly __typename?: 'NotificationResource' } + { readonly __typename?: 'NotificationNode' } & { ' $fragmentRefs'?: { 'SingleNotificationFragmentFragment': SingleNotificationFragmentFragment } } ) } }; @@ -2341,7 +2339,7 @@ export type NotificationViewerQueryVariables = Exact<{ export type NotificationViewerQuery = { readonly __typename?: 'Query', readonly notification: { readonly __typename?: 'GetNotificationByUuidResponse', readonly data: ( - { readonly __typename?: 'NotificationResource' } + { readonly __typename?: 'NotificationNode' } & { ' $fragmentRefs'?: { 'SingleNotificationFragmentFragment': SingleNotificationFragmentFragment } } ) } }; @@ -2349,7 +2347,7 @@ export type CreatePersonPageQueryVariables = Exact<{ [key: string]: never; }>; export type CreatePersonPageQuery = { readonly __typename?: 'Query', readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'TeamResource' } + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'TeamNameFragmentFragment': TeamNameFragmentFragment } } )> } }; @@ -2359,10 +2357,10 @@ export type EditPersonPageQueryVariables = Exact<{ export type EditPersonPageQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonResource' } + { readonly __typename?: 'PersonNode' } & { ' $fragmentRefs'?: { 'PersonEditorFragmentFragment': PersonEditorFragmentFragment } } ) | null }, readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( - { readonly __typename?: 'TeamResource' } + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'TeamNameFragmentFragment': TeamNameFragmentFragment } } )> } }; @@ -2372,7 +2370,7 @@ export type ViewPersonPageQueryVariables = Exact<{ export type ViewPersonPageQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonResource' } + { readonly __typename?: 'PersonNode' } & { ' $fragmentRefs'?: { 'PersonViewerFragmentFragment': PersonViewerFragmentFragment } } ) | null } }; @@ -2382,7 +2380,7 @@ export type EditTeamPageQueryVariables = Exact<{ export type EditTeamPageQuery = { readonly __typename?: 'Query', readonly team: { readonly __typename?: 'SingleTeamResponse', readonly data: ( - { readonly __typename?: 'TeamResource' } + { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'TeamEditorFragmentFragment': TeamEditorFragmentFragment } } ) } }; @@ -2392,33 +2390,33 @@ export type ViewTeamPageQueryVariables = Exact<{ export type ViewTeamPageQuery = { readonly __typename?: 'Query', readonly team: { readonly __typename?: 'SingleTeamResponse', readonly data: ( - { readonly __typename?: 'TeamResource', readonly pointEntries: ReadonlyArray<( - { readonly __typename?: 'PointEntryResource' } + { readonly __typename?: 'TeamNode', readonly pointEntries: ReadonlyArray<( + { readonly __typename?: 'PointEntryNode' } & { ' $fragmentRefs'?: { 'PointEntryTableFragmentFragment': PointEntryTableFragmentFragment } } )> } & { ' $fragmentRefs'?: { 'TeamViewerFragmentFragment': TeamViewerFragmentFragment } } ) } }; -export const SingleNotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; -export const TeamNameFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const PersonEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const TeamEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"persistentIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const PeopleTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}}]}}]} as unknown as DocumentNode; -export const TeamsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; -export const NotificationDeliveriesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; -export const NotificationsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; -export const PointEntryTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; -export const PersonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const TeamViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"captains"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; -export const ConfigFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const EventsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; -export const EventEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; -export const EventViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; -export const ImagesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const MarathonTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; -export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; -export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; -export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const SingleNotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; +export const TeamNameFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const PersonEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const TeamEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const PeopleTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; +export const TeamsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; +export const NotificationDeliveriesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; +export const NotificationsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; +export const PointEntryTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; +export const PersonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const TeamViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}}]} as unknown as DocumentNode; +export const ConfigFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; +export const EventsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; +export const EventEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const EventViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; +export const ImagesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; +export const MarathonTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; +export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; +export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; +export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"title"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"body"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"audience"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationAudienceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"url"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stageNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"title"},"value":{"kind":"Variable","name":{"kind":"Name","value":"title"}}},{"kind":"Argument","name":{"kind":"Name","value":"body"},"value":{"kind":"Variable","name":{"kind":"Name","value":"body"}}},{"kind":"Argument","name":{"kind":"Name","value":"audience"},"value":{"kind":"Variable","name":{"kind":"Name","value":"audience"}}},{"kind":"Argument","name":{"kind":"Name","value":"url"},"value":{"kind":"Variable","name":{"kind":"Name","value":"url"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const CancelNotificationScheduleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelNotificationSchedule"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"abortScheduledNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"force"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"force"},"value":{"kind":"Variable","name":{"kind":"Name","value":"force"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; @@ -2426,48 +2424,48 @@ export const SendNotificationDocument = {"kind":"Document","definitions":[{"kind export const ScheduleNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ScheduleNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduleNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"sendAt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const PersonCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const PersonEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetPersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const CreatePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const SearchPersonByNameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPersonByName"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreatePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetPersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const SearchPersonByNameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPersonByName"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreatePersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EmailAddress"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"linkblue"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"memberOf"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const PointEntryOpportunityLookupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PointEntryOpportunityLookup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pointOpportunities"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"name"}},{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"SUBSTRING"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]}}]} as unknown as DocumentNode; +export const PointEntryOpportunityLookupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PointEntryOpportunityLookup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pointOpportunities"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"name"}},{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"SUBSTRING"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreatePointOpportunityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointOpportunity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointOpportunityInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointOpportunity"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; +export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathon"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}}]}}]} as unknown as DocumentNode; -export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; -export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; -export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; +export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; +export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; +export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; +export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}}]}}]}}]} as unknown as DocumentNode; +export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]}}]} as unknown as DocumentNode; export const CommitConfigChangesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitConfigChanges"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"changes"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateConfigurationInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createConfigurations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"changes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const ConfigQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ConfigQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allConfigurations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ConfigFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const CreateEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]}}]} as unknown as DocumentNode; -export const EventsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EventsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; -export const EditEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; -export const SaveEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SaveEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const ConfigQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ConfigQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allConfigurations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ConfigFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; +export const CreateEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; +export const EventsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EventsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; +export const EditEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const SaveEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SaveEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; export const DeleteEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const ViewEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; -export const FeedPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FeedPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]}}]} as unknown as DocumentNode; -export const CreateFeedItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateFeedItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateFeedInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createFeedItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; +export const ViewEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; +export const FeedPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FeedPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreateFeedItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateFeedItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateFeedInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createFeedItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const DeleteFeedItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteFeedItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteFeedItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"feedItemUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}]}]}}]} as unknown as DocumentNode; -export const CreateImageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateImage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateImageInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createImage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const ImagesTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagesTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedNumericFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"numericFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImagesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const CreateMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const MarathonOverviewPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonOverviewPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; -export const EditMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; +export const CreateImageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateImage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateImageInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createImage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const ImagesTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagesTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedNumericFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"numericFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImagesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; +export const CreateMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const MarathonOverviewPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonOverviewPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; +export const EditMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const GetMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; -export const MarathonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; -export const AddMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathonUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; +export const MarathonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; +export const AddMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathonUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const EditMarathonHourDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditMarathonHourData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; -export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; -export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; -export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeRole"}},{"kind":"Field","name":{"kind":"Name","value":"committeeIdentifier"}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"persistentIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathonYear"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"captains"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryResource"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; +export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; +export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 3c78b165..fbdbc55d 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -1817,6 +1817,7 @@ export type TeamNode = Node & { readonly createdAt?: Maybe; readonly id: Scalars['ID']['output']; readonly legacyStatus: TeamLegacyStatus; + readonly marathon: MarathonNode; readonly members: ReadonlyArray; readonly name: Scalars['String']['output']; readonly pointEntries: ReadonlyArray; diff --git a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx index 0f8f4fda..006749ba 100644 --- a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx +++ b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx @@ -92,6 +92,7 @@ const ProfileScreen = ({ const committeeString = useMemo(() => { if (authData?.dbRole === DbRole.Committee) { if ( + // TODO: Add a way to query committee info authData.role.committeeIdentifier === CommitteeIdentifier.viceCommittee && authData.role.committeeRole === CommitteeRole.Chair diff --git a/packages/portal/src/elements/components/ImagePicker.tsx b/packages/portal/src/elements/components/ImagePicker.tsx index 7ab2fed7..de779d7f 100644 --- a/packages/portal/src/elements/components/ImagePicker.tsx +++ b/packages/portal/src/elements/components/ImagePicker.tsx @@ -9,7 +9,7 @@ const imagePickerDocument = graphql(/* GraphQL */ ` query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) { images(stringFilters: $stringFilters, pageSize: 9) { data { - uuid + id alt url } @@ -87,7 +87,7 @@ export function ImagePicker({ {group.map((image) => image ? ( diff --git a/packages/portal/src/elements/components/PersonSearch.tsx b/packages/portal/src/elements/components/PersonSearch.tsx index 151146c0..2e4e65d2 100644 --- a/packages/portal/src/elements/components/PersonSearch.tsx +++ b/packages/portal/src/elements/components/PersonSearch.tsx @@ -8,14 +8,14 @@ const personSearchDocument = graphql(/* GraphQL */ ` query PersonSearch($search: String!) { searchPeopleByName(name: $search) { data { - uuid + id name linkblue } } personByLinkBlue(linkBlueId: $search) { data { - uuid + id name linkblue } @@ -56,7 +56,7 @@ export function PersonSearch({ if (data?.personByLinkBlue.data) { options.push({ - value: data.personByLinkBlue.data.uuid, + value: data.personByLinkBlue.data.id, label: data.personByLinkBlue.data.linkblue ? `${data.personByLinkBlue.data.name} (${data.personByLinkBlue.data.linkblue})` : data.personByLinkBlue.data.name, @@ -76,7 +76,7 @@ export function PersonSearch({ const option = options.find((option) => option.value === value); if (option) { onSelect?.({ - uuid: option.person.uuid, + uuid: option.person.id, name: option.person.name ?? undefined, linkblue: option.person.linkblue ?? undefined, }); diff --git a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts index 3488fa4d..14a45524 100644 --- a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts +++ b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts @@ -6,14 +6,10 @@ export const PersonEditorFragment = graphql(/* GraphQL */ ` name linkblue email - role { - committeeRole - committeeIdentifier - } teams { position team { - uuid + id name } } diff --git a/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts b/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts index 6fbc663e..7552a9ca 100644 --- a/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts +++ b/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts @@ -4,7 +4,7 @@ export const createPointEntryDocument = graphql(/* GraphQL */ ` mutation CreatePointEntry($input: CreatePointEntryInput!) { createPointEntry(input: $input) { data { - uuid + id } } } @@ -14,7 +14,7 @@ export const getPersonByUuidDocument = graphql(/* GraphQL */ ` query GetPersonByUuid($uuid: String!) { person(uuid: $uuid) { data { - uuid + id name linkblue } @@ -26,7 +26,7 @@ export const getPersonByLinkBlueDocument = graphql(/* GraphQL */ ` query GetPersonByLinkBlue($linkBlue: String!) { personByLinkBlue(linkBlueId: $linkBlue) { data { - uuid + id name } } @@ -37,7 +37,7 @@ export const searchPersonByNameDocument = graphql(/* GraphQL */ ` query SearchPersonByName($name: String!) { searchPeopleByName(name: $name) { data { - uuid + id name } } diff --git a/packages/portal/src/elements/forms/point-entry/create/PointEntryOpportunityLookup.tsx b/packages/portal/src/elements/forms/point-entry/create/PointEntryOpportunityLookup.tsx index c10add56..06117ad5 100644 --- a/packages/portal/src/elements/forms/point-entry/create/PointEntryOpportunityLookup.tsx +++ b/packages/portal/src/elements/forms/point-entry/create/PointEntryOpportunityLookup.tsx @@ -27,7 +27,7 @@ const pointEntryOpportunityLookup = graphql(/* GraphQL */ ` ) { data { name - uuid + id } } } @@ -81,7 +81,7 @@ export function PointEntryOpportunityLookup({ .data) { if (opportunity.name) { newNameAutocomplete.push({ - value: opportunity.uuid, + value: opportunity.id, label: opportunity.name, }); } diff --git a/packages/portal/src/elements/forms/team/create/TeamCreatorGQL.ts b/packages/portal/src/elements/forms/team/create/TeamCreatorGQL.ts index 5fd31512..f313008e 100644 --- a/packages/portal/src/elements/forms/team/create/TeamCreatorGQL.ts +++ b/packages/portal/src/elements/forms/team/create/TeamCreatorGQL.ts @@ -1,8 +1,8 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const teamCreatorDocument = graphql(/* GraphQL */ ` - mutation TeamCreator($input: CreateTeamInput!) { - createTeam(input: $input) { + mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) { + createTeam(input: $input, marathon: $marathonUuid) { ok uuid } diff --git a/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts b/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts index d35e4ffb..2d862f12 100644 --- a/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts +++ b/packages/portal/src/elements/forms/team/edit/TeamEditorGQL.ts @@ -4,9 +4,11 @@ export const TeamEditorFragment = graphql(/* GraphQL */ ` fragment TeamEditorFragment on TeamNode { id name - marathonYear + marathon { + id + year + } legacyStatus - persistentIdentifier type } `); diff --git a/packages/portal/src/elements/tables/PeopleTable.tsx b/packages/portal/src/elements/tables/PeopleTable.tsx index ffe060ad..4af019a3 100644 --- a/packages/portal/src/elements/tables/PeopleTable.tsx +++ b/packages/portal/src/elements/tables/PeopleTable.tsx @@ -24,11 +24,7 @@ const PeopleTableFragment = graphql(/* GraphQL */ ` name linkblue email - role { - dbRole - committeeRole - committeeIdentifier - } + dbRole } `); @@ -179,7 +175,7 @@ export const PeopleTable = () => { } : false } - rowKey={({ uuid }) => uuid} + rowKey={({ id }) => id} sortDirections={["ascend", "descend"]} columns={[ { @@ -219,7 +215,7 @@ export const PeopleTable = () => { title: "Role", dataIndex: "dbRole", render: (_, record) => { - return stringifyDbRole(record.role.dbRole); + return stringifyDbRole(record.dbRole); }, sorter: true, sortDirections: ["ascend", "descend"], @@ -232,6 +228,7 @@ export const PeopleTable = () => { title: "Committee Role", dataIndex: "committeeRole", render: (_, record) => { + // TODO: fix return record.role.committeeRole ?? "None"; }, sorter: true, @@ -245,6 +242,7 @@ export const PeopleTable = () => { title: "Committee Name", dataIndex: "committeeName", render: (_, record) => { + // TODO: fix return record.role.committeeIdentifier ? committeeNames[record.role.committeeIdentifier] : "None"; @@ -266,7 +264,7 @@ export const PeopleTable = () => { onClick={() => navigate({ to: "/people/$personId/", - params: { personId: record.uuid }, + params: { personId: record.id }, }).catch((error: unknown) => console.error(error)) } icon={} @@ -275,7 +273,7 @@ export const PeopleTable = () => { onClick={() => navigate({ to: "/people/$personId/edit", - params: { personId: record.uuid }, + params: { personId: record.id }, }).catch((error: unknown) => console.error(error)) } icon={} diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index a6f4b4f9..1b1a7623 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -46,7 +46,10 @@ export const TeamsTableFragment = graphql(/* GraphQL */ ` type name legacyStatus - marathonYear + marathon { + id + year + } totalPoints } `); @@ -173,7 +176,7 @@ export const TeamsTable = () => { onClick={() => navigate({ to: "/teams/$teamId/", - params: { teamId: record.uuid }, + params: { teamId: record.id }, }).catch((error: unknown) => console.error(error)) } icon={} @@ -182,7 +185,7 @@ export const TeamsTable = () => { onClick={() => navigate({ to: "/teams/$teamId/edit", - params: { teamId: record.uuid }, + params: { teamId: record.id }, }).catch((error: unknown) => console.error(error)) } icon={} @@ -195,7 +198,7 @@ export const TeamsTable = () => { getFragmentData(TeamsTableFragment, data?.teams.data) ?? undefined } loading={fetching} - rowKey={({ uuid }) => uuid} + rowKey={({ id }) => id} pagination={ data ? { diff --git a/packages/portal/src/elements/viewers/team/TeamViewer.tsx b/packages/portal/src/elements/viewers/team/TeamViewer.tsx index e8c367ba..cdcdd230 100644 --- a/packages/portal/src/elements/viewers/team/TeamViewer.tsx +++ b/packages/portal/src/elements/viewers/team/TeamViewer.tsx @@ -1,5 +1,6 @@ import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; import { Link, useNavigate } from "@tanstack/react-router"; +import { MembershipPositionType } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData, @@ -13,7 +14,10 @@ export const TeamViewerFragment = graphql(/* GraphQL */ ` fragment TeamViewerFragment on TeamNode { id name - marathonYear + marathon { + id + year + } legacyStatus totalPoints type @@ -38,7 +42,7 @@ export function TeamViewer({ const navigate = useNavigate(); const { TeamDeletePopup, showModal } = useTeamDeletePopup({ - uuid: teamData?.uuid ?? "", + uuid: teamData?.id ?? "", onDelete: () => { navigate({ to: "/teams/" }).catch((error: unknown) => console.error(error) @@ -57,7 +61,7 @@ export function TeamViewer({ {teamData.name} - {teamData.marathonYear} + {teamData.marathon.year} {teamData.legacyStatus} @@ -82,7 +86,7 @@ export function TeamViewer({ onClick={() => { navigate({ to: "/teams/$teamId/edit", - params: { teamId: teamData.uuid }, + params: { teamId: teamData.id }, }).catch((error: unknown) => console.error(error)); }} icon={} @@ -101,29 +105,33 @@ export function TeamViewer({ >
    - {teamData.captains.map((captain) => ( -
  • - - {captain.person.name ?? "Never logged in"} ( - {captain.person.linkblue ?? "No linkblue"}) - -
  • - ))} + {teamData.members + .filter( + ({ position }) => position === MembershipPositionType.Captain + ) + .map((captain) => ( +
  • + + {captain.person.name ?? "Never logged in"} ( + {captain.person.linkblue ?? "No linkblue"}) + +
  • + ))}
    {teamData.members.map((member) => ( -
  • +
  • {member.person.name ?? "Never logged in"} ( diff --git a/packages/portal/src/hooks/useLoginState.ts b/packages/portal/src/hooks/useLoginState.ts index cf1cfbd0..d2dd2442 100644 --- a/packages/portal/src/hooks/useLoginState.ts +++ b/packages/portal/src/hooks/useLoginState.ts @@ -1,5 +1,5 @@ import type { Authorization } from "@ukdanceblue/common"; -import { RoleResource, defaultAuthorization } from "@ukdanceblue/common"; +import { AccessLevel, defaultAuthorization } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; @@ -7,11 +7,7 @@ const loginStateDocument = graphql(/* GraphQL */ ` query LoginState { loginState { loggedIn - role { - dbRole - committeeRole - committeeIdentifier - } + dbRole } } `); @@ -41,6 +37,11 @@ export function useLoginState(): { return { loggedIn: data.loginState.loggedIn, - authorization: RoleResource.init(data.loginState.role).toAuthorization(), + authorization: { + dbRole: data.loginState.dbRole, + // TODO: Add committee info back here + accessLevel: AccessLevel.Public, + committees: [], + }, }; } diff --git a/packages/portal/src/pages/events/create-event/EventCreatorGQL.ts b/packages/portal/src/pages/events/create-event/EventCreatorGQL.ts index 00648bdb..0dd4c24b 100644 --- a/packages/portal/src/pages/events/create-event/EventCreatorGQL.ts +++ b/packages/portal/src/pages/events/create-event/EventCreatorGQL.ts @@ -4,7 +4,7 @@ export const eventCreatorDocument = graphql(/* GraphQL */ ` mutation CreateEvent($input: CreateEventInput!) { createEvent(input: $input) { data { - uuid + id } } } diff --git a/packages/portal/src/pages/feed/FeedPage.tsx b/packages/portal/src/pages/feed/FeedPage.tsx index 63bf4b78..2ef2981a 100644 --- a/packages/portal/src/pages/feed/FeedPage.tsx +++ b/packages/portal/src/pages/feed/FeedPage.tsx @@ -19,7 +19,7 @@ import { useClient, useQuery } from "urql"; const feedPageDocument = graphql(/* GraphQL */ ` query FeedPage { feed(limit: null) { - uuid + id title createdAt textContent @@ -34,7 +34,7 @@ const feedPageDocument = graphql(/* GraphQL */ ` const createFeedItemDocument = graphql(/* GraphQL */ ` mutation CreateFeedItem($input: CreateFeedInput!) { createFeedItem(input: $input) { - uuid + id } } `); @@ -155,7 +155,7 @@ export function FeedPage() { {result.data?.feed.map((feedItem) => ( - + { await client .mutation(deleteFeedItemDocument, { - uuid: feedItem.uuid, + uuid: feedItem.id, }) .toPromise(); setTimeout( diff --git a/packages/portal/src/pages/images/list/CreateImagePopup.tsx b/packages/portal/src/pages/images/list/CreateImagePopup.tsx index 746231ba..9b44ae8b 100644 --- a/packages/portal/src/pages/images/list/CreateImagePopup.tsx +++ b/packages/portal/src/pages/images/list/CreateImagePopup.tsx @@ -8,7 +8,7 @@ import { useClient } from "urql"; const createImageDocument = graphql(/* GraphQL */ ` mutation CreateImage($input: CreateImageInput!) { createImage(input: $input) { - uuid + id } } `); @@ -42,7 +42,7 @@ export function CreateImagePopup({ if (error) { void showErrorMessage(error.message); } - onClose(data.createImage.uuid); + onClose(data.createImage.id); } else { void showErrorMessage(error?.message ?? "An unknown error occurred"); } diff --git a/packages/portal/src/pages/marathon/create/useMarathonCreatorForm.ts b/packages/portal/src/pages/marathon/create/useMarathonCreatorForm.ts index 18b4b97f..b405f17b 100644 --- a/packages/portal/src/pages/marathon/create/useMarathonCreatorForm.ts +++ b/packages/portal/src/pages/marathon/create/useMarathonCreatorForm.ts @@ -11,7 +11,7 @@ export function useMarathonCreatorForm() { graphql(/* GraphQL */ ` mutation CreateMarathon($input: CreateMarathonInput!) { createMarathon(input: $input) { - uuid + id } } `) @@ -67,7 +67,7 @@ export function useMarathonCreatorForm() { resetWatcher(); await navigate({ to: "/marathon/$marathonId/", - params: { marathonId: data.createMarathon.uuid }, + params: { marathonId: data.createMarathon.id }, }); } }, diff --git a/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts b/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts index 85f72471..30fe02dc 100644 --- a/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts +++ b/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts @@ -13,7 +13,7 @@ export function useMarathonCreatorForm({ marathonId }: { marathonId: string }) { graphql(/* GraphQL */ ` mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) { setMarathon(input: $input, uuid: $marathonId) { - uuid + id } } `) @@ -55,8 +55,10 @@ export function useMarathonCreatorForm({ marathonId }: { marathonId: string }) { }>({ defaultValues: { year: existingData?.marathon.year, - startDate: dateTimeFromSomething(existingData?.marathon.startDate), - endDate: dateTimeFromSomething(existingData?.marathon.endDate), + startDate: + dateTimeFromSomething(existingData?.marathon.startDate) ?? undefined, + endDate: + dateTimeFromSomething(existingData?.marathon.endDate) ?? undefined, }, onChange: ({ startDate, endDate }) => { if (startDate && endDate && startDate.toMillis() > endDate.toMillis()) { @@ -94,7 +96,7 @@ export function useMarathonCreatorForm({ marathonId }: { marathonId: string }) { resetExistingWatcher(); await navigate({ to: "/marathon/$marathonId/", - params: { marathonId: data.setMarathon.uuid }, + params: { marathonId: data.setMarathon.id }, }); } }, diff --git a/packages/portal/src/pages/marathon/single/view/hour/add/AddMarathonHourPage.tsx b/packages/portal/src/pages/marathon/single/view/hour/add/AddMarathonHourPage.tsx index 88d16fe9..920a0cb7 100644 --- a/packages/portal/src/pages/marathon/single/view/hour/add/AddMarathonHourPage.tsx +++ b/packages/portal/src/pages/marathon/single/view/hour/add/AddMarathonHourPage.tsx @@ -19,7 +19,7 @@ export function AddMarathonHourPage() { $marathonUuid: String! ) { createMarathonHour(input: $input, marathonUuid: $marathonUuid) { - uuid + id } } `) diff --git a/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx b/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx index 7627be01..6149129d 100644 --- a/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx +++ b/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx @@ -26,7 +26,7 @@ const editMarathonHourDataDocument = graphql(/* GraphQL */ ` const editMarathonHourDocument = graphql(/* GraphQL */ ` mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) { setMarathonHour(input: $input, uuid: $uuid) { - uuid + id } } `); diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index 1a1e8224..399a5022 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -205,6 +205,14 @@ export class TeamRepository { }); } + getMarathon(team: SimpleUniqueParam) { + return this.prisma.team + .findUnique({ + where: team, + }) + .marathon(); + } + createTeam( data: { name: string; diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index be106e11..a3d30621 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -36,6 +36,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; import { membershipModelToResource } from "../repositories/membership/membershipModelToResource.js"; import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; import { TeamRepository } from "../repositories/team/TeamRepository.js"; @@ -360,4 +361,16 @@ export class TeamResolver { return result._sum.points ?? 0; } + + @AccessControl({ accessLevel: AccessLevel.Public }) + @FieldResolver(() => Common.MarathonNode) + async marathon(@Root() team: TeamNode): Promise { + const result = await this.teamRepository.getMarathon({ uuid: team.id }); + + if (result == null) { + throw new DetailedError(ErrorCode.NotFound, "Team not found"); + } + + return marathonModelToResource(result); + } } diff --git a/schema.graphql b/schema.graphql index 52c56894..c4a34460 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1842,6 +1842,7 @@ type TeamNode implements Node { createdAt: DateTimeISO id: ID! legacyStatus: TeamLegacyStatus! + marathon: MarathonNode! members: [MembershipNode!]! name: String! pointEntries: [PointEntryNode!]! From fe9aac9013a5f65a44c9d0852a423a218a85b64b Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 17:47:30 +0000 Subject: [PATCH 047/153] Change some `uuid`s to `id`s --- .../forms/notification/manage/ManageNotificationForm.tsx | 2 +- .../src/elements/forms/person/create/PersonCreator.tsx | 8 ++++---- .../src/elements/forms/person/edit/PersonEditor.tsx | 8 ++++---- .../src/elements/forms/person/edit/usePersonEditorForm.ts | 6 +++--- .../forms/point-entry/create/PointEntryPersonLookup.tsx | 8 +++----- .../src/elements/forms/team/edit/useTeamEditorForm.ts | 4 ++-- .../tables/notification/NotificationDeliveriesTable.tsx | 2 +- .../elements/tables/notification/NotificationsTable.tsx | 2 +- .../src/elements/tables/point-entry/PointEntryTable.tsx | 2 +- .../portal/src/elements/viewers/person/PersonViewer.tsx | 8 ++++---- packages/portal/src/pages/config/useConfig.ts | 2 +- .../portal/src/pages/events/list-events/EventsTable.tsx | 2 +- .../events/single-event/edit-event/useEventEditorForm.ts | 2 +- .../pages/events/single-event/view-event/EventViewer.tsx | 4 ++-- packages/portal/src/pages/images/list/ImagesTable.tsx | 4 ++-- .../src/pages/marathon/single/view/MarathonViewer.tsx | 6 +++--- 16 files changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/portal/src/elements/forms/notification/manage/ManageNotificationForm.tsx b/packages/portal/src/elements/forms/notification/manage/ManageNotificationForm.tsx index 58ab0018..624f6546 100644 --- a/packages/portal/src/elements/forms/notification/manage/ManageNotificationForm.tsx +++ b/packages/portal/src/elements/forms/notification/manage/ManageNotificationForm.tsx @@ -36,7 +36,7 @@ export const ManageNotificationForm = ({ notificationFragment ); const actions = useNotificationManagerForm({ - uuid: notification?.uuid ?? "", + uuid: notification?.id ?? "", }); const [sendAt, setSendAt] = useState( diff --git a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx index b3e9bc36..35cce087 100644 --- a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx +++ b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx @@ -49,13 +49,13 @@ export function PersonCreator({ for (const team of teamNamesData ?? []) { captaincyOptions.push({ label: team.name, - value: team.uuid, - disabled: formMemberOf.includes(team.uuid), + value: team.id, + disabled: formMemberOf.includes(team.id), }); membershipOptions.push({ label: team.name, - value: team.uuid, - disabled: formCaptainOf.includes(team.uuid), + value: team.id, + disabled: formCaptainOf.includes(team.id), }); } return { captaincyOptions, membershipOptions }; diff --git a/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx b/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx index ce5321de..136b360e 100644 --- a/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx +++ b/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx @@ -49,13 +49,13 @@ export function PersonEditor({ for (const team of teamNamesData ?? []) { captaincyOptions.push({ label: team.name, - value: team.uuid, - disabled: formMemberOf.includes(team.uuid), + value: team.id, + disabled: formMemberOf.includes(team.id), }); membershipOptions.push({ label: team.name, - value: team.uuid, - disabled: formCaptainOf.includes(team.uuid), + value: team.id, + disabled: formCaptainOf.includes(team.id), }); } return { captaincyOptions, membershipOptions }; diff --git a/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts b/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts index 7e266a7b..bb8100b5 100644 --- a/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts +++ b/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts @@ -45,14 +45,14 @@ export function usePersonEditorForm( (membership) => membership.position === MembershipPositionType.Captain ) - .map((membership) => membership.team.uuid) ?? [], + .map((membership) => membership.team.id) ?? [], memberOf: personData?.teams .filter( (membership) => membership.position === MembershipPositionType.Member ) - .map((membership) => membership.team.uuid) ?? [], + .map((membership) => membership.team.id) ?? [], }, onChange: (values) => { const memberOfCount: Record = {}; @@ -101,7 +101,7 @@ export function usePersonEditorForm( const dbRole: DbRole = DbRole.None; const { data } = await setPerson({ - uuid: personData.uuid, + uuid: personData.id, input: { name: values.name || null, linkblue: values.linkblue || null, diff --git a/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx b/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx index 7a0c783b..fa15f0f0 100644 --- a/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx +++ b/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx @@ -73,13 +73,11 @@ export function PointEntryPersonLookup({ useEffect(() => { if (getPersonByLinkBlueQuery.data?.personByLinkBlue.data) { - setPersonFromUuid( - getPersonByLinkBlueQuery.data.personByLinkBlue.data.uuid - ); + setPersonFromUuid(getPersonByLinkBlueQuery.data.personByLinkBlue.data.id); } }, [ getPersonByLinkBlueQuery.data?.personByLinkBlue.data, - getPersonByLinkBlueQuery.data?.personByLinkBlue.data?.uuid, + getPersonByLinkBlueQuery.data?.personByLinkBlue.data?.id, setPersonFromUuid, ]); @@ -133,7 +131,7 @@ export function PointEntryPersonLookup({ for (const person of searchByNameQuery.data.searchPeopleByName.data) { if (person.name) { newNameAutocomplete.push({ - value: person.uuid, + value: person.id, label: person.name, }); } diff --git a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts index 6ba07565..71051c24 100644 --- a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts +++ b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts @@ -39,12 +39,12 @@ export function useTeamEditorForm( type: teamData?.type ?? TeamType.Spirit, }, onSubmit: async (values) => { - if (!teamData?.uuid) { + if (!teamData?.id) { throw new Error("Team UUID is required"); } const { data } = await setTeam({ - uuid: teamData.uuid, + uuid: teamData.id, input: { name: values.name ?? null, legacyStatus: values.legacyStatus ?? null, diff --git a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx index 72188e31..f5aafeeb 100644 --- a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx @@ -105,7 +105,7 @@ export const NotificationDeliveriesTable = ({ <> uuid} + rowKey={({ id }) => id} loading={fetching} pagination={ notificationDeliveriesDocument diff --git a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx index 081c412d..28f0a5ac 100644 --- a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx @@ -109,7 +109,7 @@ export const NotificationsTable = () => { <>
    uuid} + rowKey={({ id }) => id} loading={fetching} pagination={ notificationsDocument diff --git a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx index a820b93c..6577a5a9 100644 --- a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx +++ b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx @@ -99,7 +99,7 @@ export function PointEntryTable({ render: (_, record) => (
    uuid} + rowKey={({ id }) => id} loading={fetching} pagination={ eventsDocument diff --git a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts index e9120860..6d2b67aa 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts +++ b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts @@ -53,7 +53,7 @@ export function useEventEditorForm( } await setEvent({ - uuid: eventData.uuid, + uuid: eventData.id, input: { title: values.title, summary: values.summary ?? eventData.summary ?? null, diff --git a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx index 5b090201..2094873b 100644 --- a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx +++ b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx @@ -65,7 +65,7 @@ export function EventViewer({ const navigate = useNavigate(); const { EventDeletePopup, showModal } = useEventDeletePopup({ - uuid: eventData?.uuid ?? "", + uuid: eventData?.id ?? "", onDelete: () => { navigate({ to: "/events" }).catch((error: unknown) => console.error(error) @@ -96,7 +96,7 @@ export function EventViewer({ {eventData.title} diff --git a/packages/portal/src/pages/images/list/ImagesTable.tsx b/packages/portal/src/pages/images/list/ImagesTable.tsx index 5a795c8d..a6086812 100644 --- a/packages/portal/src/pages/images/list/ImagesTable.tsx +++ b/packages/portal/src/pages/images/list/ImagesTable.tsx @@ -124,7 +124,7 @@ export const ImagesTable = () => { {
    uuid} + rowKey={({ id }) => id} loading={fetching} pagination={ imagesDocument diff --git a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx index c606fe30..4cc073ce 100644 --- a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx +++ b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx @@ -62,7 +62,7 @@ export const MarathonViewer = ({ Hours Add @@ -72,12 +72,12 @@ export const MarathonViewer = ({ > {sortedHours.map((hour) => ( {hour.title} From 0dacdfbe5ec1aeda6f2d763e6d8b695d22d07a4c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 21:04:17 +0000 Subject: [PATCH 048/153] Add more support for passing committee info to client --- .../common/lib/api/resources/Membership.ts | 31 +++ packages/common/lib/api/resources/index.ts | 1 + .../lib/api/types/EffectiveCommitteeRole.ts | 25 +++ .../common/lib/authorization/accessControl.ts | 2 + .../committee/CommitteeRepository.ts | 26 +++ .../repositories/device/DeviceRepository.ts | 10 +- .../membership/membershipModelToResource.ts | 28 ++- .../repositories/person/PersonRepository.ts | 180 ++++++++++++++++-- packages/server/src/resolvers/LoginState.ts | 14 +- .../server/src/resolvers/MarathonResolver.ts | 118 +++++++++++- .../server/src/resolvers/PersonResolver.ts | 41 ++-- packages/server/src/resolvers/context.ts | 9 + schema.graphql | 54 +++++- 13 files changed, 501 insertions(+), 38 deletions(-) create mode 100644 packages/common/lib/api/types/EffectiveCommitteeRole.ts diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index c437d9c6..2f4aab19 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -1,5 +1,9 @@ import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; +import { + CommitteeIdentifier, + CommitteeRole, +} from "../../authorization/structures.js"; import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -39,5 +43,32 @@ export class MembershipNode extends TimestampedResource implements Node { } } +@ObjectType({ + implements: [Node], +}) +export class CommitteeMembershipNode extends MembershipNode implements Node { + @Field(() => CommitteeRole) + role!: CommitteeRole; + + @Field(() => CommitteeIdentifier) + identifier!: CommitteeIdentifier; + + public static init(init: { + id: string; + position: MembershipPositionType; + identifier: CommitteeIdentifier; + role: CommitteeRole; + createdAt?: Date | null; + updatedAt?: Date | null; + }) { + return CommitteeMembershipNode.doInit(init); + } +} + export const { MembershipConnection, MembershipEdge, MembershipResult } = createNodeClasses(MembershipNode, "Membership"); +export const { + CommitteeMembershipConnection, + CommitteeMembershipEdge, + CommitteeMembershipResult, +} = createNodeClasses(CommitteeMembershipNode, "CommitteeMembership"); diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index c19e5a24..1e14c754 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,4 +1,5 @@ export { AuthIdPairResource as AuthIdPairNode } from "../types/AuthIdPair.js"; +export { EffectiveCommitteeRole } from "../types/EffectiveCommitteeRole.js"; export { IntervalISO } from "../types/IntervalISO.js"; export * from "./Committee.js"; diff --git a/packages/common/lib/api/types/EffectiveCommitteeRole.ts b/packages/common/lib/api/types/EffectiveCommitteeRole.ts new file mode 100644 index 00000000..d038c16b --- /dev/null +++ b/packages/common/lib/api/types/EffectiveCommitteeRole.ts @@ -0,0 +1,25 @@ +import { Field, ObjectType } from "type-graphql"; + +import { + CommitteeIdentifier, + CommitteeRole, +} from "../../authorization/structures.js"; + +@ObjectType("EffectiveCommitteeRole") +export class EffectiveCommitteeRole { + @Field(() => CommitteeIdentifier) + committee!: CommitteeIdentifier; + + @Field(() => CommitteeRole) + role!: CommitteeRole; + + public static init( + committee: CommitteeIdentifier, + role: CommitteeRole + ): EffectiveCommitteeRole { + const effectiveCommitteeRole = new this(); + effectiveCommitteeRole.committee = committee; + effectiveCommitteeRole.role = role; + return effectiveCommitteeRole; + } +} diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 41293f65..15a25729 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -7,6 +7,7 @@ import type { Authorization, CommitteeRole, DbRole, + EffectiveCommitteeRole, PersonNode, UserData, } from "../index.js"; @@ -170,6 +171,7 @@ export interface AccessControlParam< export interface AuthorizationContext { authenticatedUser: PersonNode | null; + effectiveCommitteeRoles: EffectiveCommitteeRole[]; userData: UserData; } diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index 5b3274a5..d08ad15d 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -160,6 +160,32 @@ export class CommitteeRepository { }); } + async getCommitteeTeam( + committee: CommitteeIdentifier, + marathon: UniqueMarathonParam + ) { + const result = await this.prisma.committee + .findUnique({ where: { identifier: committee } }) + .correspondingTeams({ + where: { + marathon, + }, + }); + if (result?.length === 1) { + return result[0]; + } else if (result?.length === 0) { + throw new DetailedError( + ErrorCode.NotFound, + "No team found for the given committee and marathon" + ); + } else { + throw new DetailedError( + ErrorCode.InternalFailure, + "Multiple teams found for the given committee and marathon" + ); + } + } + getChildCommittees(identifier: CommitteeUniqueParam) { return this.prisma.committee .findUnique({ diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index e90b4198..d28763f7 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -42,7 +42,9 @@ export class DeviceRepository { return device?.lastSeenPersonId == null ? null - : this.personRepository.findPersonById(device.lastSeenPersonId); + : this.personRepository.findPersonByUnique({ + id: device.lastSeenPersonId, + }); } async listDevices({ @@ -98,7 +100,9 @@ export class DeviceRepository { let user: Person | null = null; if (lastUserId != null) { - user = await this.personRepository.findPersonByUuid(lastUserId); + user = await this.personRepository.findPersonByUnique({ + uuid: lastUserId, + }); if (user == null) { throw new Error("Last user not found"); } @@ -189,7 +193,7 @@ export class DeviceRepository { }, }); } - + if (where.length === 0) { throw new Error("Not implemented"); } diff --git a/packages/server/src/repositories/membership/membershipModelToResource.ts b/packages/server/src/repositories/membership/membershipModelToResource.ts index 4565d5f1..f0002e50 100644 --- a/packages/server/src/repositories/membership/membershipModelToResource.ts +++ b/packages/server/src/repositories/membership/membershipModelToResource.ts @@ -1,5 +1,11 @@ import type { Membership } from "@prisma/client"; -import { MembershipNode } from "@ukdanceblue/common"; +import type { CommitteeIdentifier } from "@ukdanceblue/common"; +import { + CommitteeMembershipNode, + DetailedError, + ErrorCode, + MembershipNode, +} from "@ukdanceblue/common"; export function membershipModelToResource( membershipModel: Membership @@ -11,3 +17,23 @@ export function membershipModelToResource( updatedAt: membershipModel.updatedAt, }); } + +export function committeeMembershipModelToResource( + membershipModel: Membership, + committeeIdentifier: CommitteeIdentifier +): CommitteeMembershipNode { + if (!membershipModel.committeeRole) { + throw new DetailedError( + ErrorCode.PreconditionsFailed, + "Committee role is required" + ); + } + return CommitteeMembershipNode.init({ + id: membershipModel.uuid, + position: membershipModel.position, + identifier: committeeIdentifier, + role: membershipModel.committeeRole, + createdAt: membershipModel.createdAt, + updatedAt: membershipModel.updatedAt, + }); +} diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index e7613907..62348b39 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -1,19 +1,23 @@ -import type { Person } from "@prisma/client"; +import type { Committee, Membership, Person } from "@prisma/client"; import { Prisma, PrismaClient } from "@prisma/client"; import { AuthSource, + CommitteeIdentifier, CommitteeRole, DbRole, DetailedError, + EffectiveCommitteeRole, ErrorCode, MembershipPositionType, SortDirection, TeamLegacyStatus, + TeamType, } from "@ukdanceblue/common"; import { Service } from "typedi"; import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; @@ -87,21 +91,6 @@ export class PersonRepository { ); } - /** @deprecated Use findPersonByUnique directly */ - findPersonByUuid(uuid: string): Promise { - return this.prisma.person.findUnique({ where: { uuid } }); - } - - /** @deprecated Use findPersonByUnique directly */ - findPersonById(id: number): Promise { - return this.prisma.person.findUnique({ where: { id } }); - } - - /** @deprecated Use findPersonByUnique directly */ - findPersonByLinkblue(linkblue: string): Promise { - return this.prisma.person.findUnique({ where: { linkblue } }); - } - async findPersonByUnique(param: UniquePersonParam) { return this.prisma.person.findUnique({ where: param }); } @@ -144,6 +133,73 @@ export class PersonRepository { return DbRole.Public; } + async getEffectiveCommitteeRolesOfPerson( + param: UniquePersonParam + ): Promise { + const effectiveCommitteeRoles: EffectiveCommitteeRole[] = []; + + const committees = await this.prisma.membership.findMany({ + where: { + person: param, + team: { + type: TeamType.Committee, + }, + }, + select: { + team: { + select: { + correspondingCommittee: { + select: { + identifier: true, + parentCommittee: { + select: { + identifier: true, + }, + }, + childCommittees: { + select: { + identifier: true, + }, + }, + }, + }, + }, + }, + committeeRole: true, + }, + }); + + for (const committee of committees) { + if (committee.team.correspondingCommittee) { + if (!committee.committeeRole) { + throw new DetailedError(ErrorCode.InternalFailure, "No role found"); + } + const role = EffectiveCommitteeRole.init( + committee.team.correspondingCommittee.identifier, + committee.committeeRole + ); + effectiveCommitteeRoles.push(role); + if (committee.team.correspondingCommittee.parentCommittee) { + const parentRole = EffectiveCommitteeRole.init( + committee.team.correspondingCommittee.parentCommittee.identifier, + CommitteeRole.Member + ); + effectiveCommitteeRoles.push(parentRole); + } + const childRoles = + committee.team.correspondingCommittee.childCommittees.map((child) => + EffectiveCommitteeRole.init( + child.identifier, + committee.committeeRole! + ) + ); + effectiveCommitteeRoles.push(...childRoles); + } + } + + return effectiveCommitteeRoles; + } + listPeople({ filters, order, @@ -511,4 +567,96 @@ export class PersonRepository { }, }); } + + public async getPrimaryCommitteeOfPerson( + person: UniquePersonParam, + marathon?: UniqueMarathonParam + ): Promise<[Membership, Committee] | null> { + const committees = await this.prisma.membership.findMany({ + where: { + person, + team: { + marathon, + type: TeamType.Committee, + }, + }, + include: { + team: { + include: { + correspondingCommittee: true, + }, + }, + }, + }); + + if (committees.length === 0) { + return null; + } + + let bestCommittee = undefined; + let fallbackCommittee = undefined; + + for (let i = 1; i <= committees.length; i++) { + const committee = committees[i]; + if (committee) { + // We don't want to return the overall committee or vice committee if we have a better option + if ( + committee.team.correspondingCommittee?.identifier === + CommitteeIdentifier.overallCommittee || + committee.team.correspondingCommittee?.identifier === + CommitteeIdentifier.viceCommittee + ) { + fallbackCommittee = committee; + continue; + } + + if (bestCommittee) { + if ( + committee.committeeRole === CommitteeRole.Chair && + bestCommittee.committeeRole !== CommitteeRole.Chair + ) { + bestCommittee = committee; + continue; + } else if ( + committee.committeeRole === CommitteeRole.Coordinator && + !( + bestCommittee.committeeRole === CommitteeRole.Coordinator || + bestCommittee.committeeRole === CommitteeRole.Chair + ) + ) { + bestCommittee = committee; + continue; + } + } else { + bestCommittee = committee; + } + } + } + + if (bestCommittee) { + if ( + !bestCommittee.team.correspondingCommittee || + !bestCommittee.committeeRole + ) { + throw new DetailedError( + ErrorCode.InternalFailure, + "Invalid committee assignment" + ); + } + return [bestCommittee, bestCommittee.team.correspondingCommittee]; + } else if (fallbackCommittee) { + if ( + !fallbackCommittee.team.correspondingCommittee || + !fallbackCommittee.committeeRole + ) { + throw new DetailedError( + ErrorCode.InternalFailure, + "Invalid committee assignment" + ); + } + return [fallbackCommittee, fallbackCommittee.team.correspondingCommittee]; + } else { + return null; + } + } } diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index dfae09e7..99143b3c 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -1,4 +1,9 @@ -import { AuthSource, DbRole } from "@ukdanceblue/common"; +import { + AuthSource, + DbRole, + EffectiveCommitteeRole, + PersonNode, +} from "@ukdanceblue/common"; import { Ctx, Field, ObjectType, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; @@ -14,6 +19,12 @@ export class LoginState { @Field(() => AuthSource) authSource!: AuthSource; + + @Field(() => [EffectiveCommitteeRole]) + effectiveCommitteeRoles!: EffectiveCommitteeRole[]; + + @Field(() => PersonNode, { nullable: true }) + person?: PersonNode; } @Resolver(() => LoginState) @@ -23,6 +34,7 @@ export class LoginStateResolver { loginState(@Ctx() ctx: Context.GraphQLContext): LoginState { return { loggedIn: ctx.authenticatedUser != null, + effectiveCommitteeRoles: ctx.effectiveCommitteeRoles, dbRole: ctx.userData.auth.dbRole, authSource: ctx.userData.authSource, }; diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 9ffad575..0a46f6ed 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -1,10 +1,12 @@ import { + CommitteeIdentifier, DetailedError, ErrorCode, FilteredListQueryArgs, MarathonHourNode, MarathonNode, SortDirection, + TeamNode, } from "@ukdanceblue/common"; import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; import { @@ -22,9 +24,11 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import type { CommitteeRepository } from "../repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; import { marathonHourModelToResource } from "../repositories/marathonHour/marathonHourModelToResource.js"; +import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @@ -76,8 +80,17 @@ class ListMarathonsArgs extends FilteredListQueryArgs< @Resolver(() => MarathonNode) @Service() -export class MarathonResolver { - constructor(private readonly marathonRepository: MarathonRepository) {} +export class MarathonResolver + implements + Record< + `${CommitteeIdentifier}Team`, + (marathon: MarathonNode) => Promise + > +{ + constructor( + private readonly marathonRepository: MarathonRepository, + private readonly committeeRepository: CommitteeRepository + ) {} @Query(() => MarathonNode) async marathon(@Arg("uuid") uuid: string) { @@ -181,4 +194,105 @@ export class MarathonResolver { }); return rows.map(marathonHourModelToResource); } + + async #committeeTeam(committee: CommitteeIdentifier, marathon: MarathonNode) { + const result = await this.committeeRepository.getCommitteeTeam(committee, { + uuid: marathon.id, + }); + if (result == null) { + throw new DetailedError( + ErrorCode.NotFound, + "No team found for the given committee and marathon" + ); + } + return teamModelToResource(result); + } + + // Committees + @FieldResolver(() => TeamNode) + async communityDevelopmentCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.communityDevelopmentCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async programmingCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.programmingCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async fundraisingCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.fundraisingCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async dancerRelationsCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.dancerRelationsCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async familyRelationsCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.familyRelationsCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async techCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam(CommitteeIdentifier.techCommittee, marathon); + } + + @FieldResolver(() => TeamNode) + async operationsCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.operationsCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async marketingCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.marketingCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async corporateCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.corporateCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async miniMarathonsCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam( + CommitteeIdentifier.miniMarathonsCommittee, + marathon + ); + } + + @FieldResolver(() => TeamNode) + async viceCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam(CommitteeIdentifier.viceCommittee, marathon); + } + + @FieldResolver(() => TeamNode) + async overallCommitteeTeam(marathon: MarathonNode) { + return this.#committeeTeam(CommitteeIdentifier.overallCommittee, marathon); + } } diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 3b492b57..762d433d 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -1,6 +1,7 @@ import { AccessControl, AccessLevel, + CommitteeMembershipNode, DbRole, DetailedError, ErrorCode, @@ -29,7 +30,10 @@ import { Service } from "typedi"; import { auditLogger } from "../lib/logging/auditLogging.js"; import type { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; -import { membershipModelToResource } from "../repositories/membership/membershipModelToResource.js"; +import { + committeeMembershipModelToResource, + membershipModelToResource, +} from "../repositories/membership/membershipModelToResource.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; @@ -380,22 +384,31 @@ export class PersonResolver { return models.map((row) => membershipModelToResource(row)); } - @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @FieldResolver(() => [MembershipNode], { - deprecationReason: "Use teams instead and filter by position", - }) - async captaincies(@Root() person: PersonNode): Promise { - const models = await this.personRepository.findMembershipsOfPerson( - { - uuid: person.id, - }, - { position: MembershipPositionType.Captain } - ); + @AccessControl( + { accessLevel: AccessLevel.Committee }, + { + rootMatch: [ + { + root: "uuid", + extractor: (userData) => userData.userId, + }, + ], + } + ) + @FieldResolver(() => CommitteeMembershipNode) + async primaryCommittee( + @Root() person: PersonNode + ): Promise { + const models = await this.personRepository.getPrimaryCommitteeOfPerson({ + uuid: person.id, + }); if (models == null) { - return []; + return null; } - return models.map((row) => membershipModelToResource(row)); + const [membership, committee] = models; + + return committeeMembershipModelToResource(membership, committee.identifier); } } diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index a845dbe8..c555fcd0 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -28,6 +28,7 @@ export const graphqlContextFunction: ContextFunction< if (!token) { return { authenticatedUser: null, + effectiveCommitteeRoles: [], userData: { auth: defaultAuthorization, authSource: AuthSource.None, @@ -40,6 +41,7 @@ export const graphqlContextFunction: ContextFunction< logger.trace("graphqlContextFunction No userId found"); return { authenticatedUser: null, + effectiveCommitteeRoles: [], userData: { auth, authSource, @@ -59,9 +61,15 @@ export const graphqlContextFunction: ContextFunction< personRepository ); + const effectiveCommitteeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ + id: person.id, + }); + logger.trace("graphqlContextFunction Found user", personResource); return { authenticatedUser: personResource, + effectiveCommitteeRoles, userData: { auth, userId, @@ -77,6 +85,7 @@ export const graphqlContextFunction: ContextFunction< logger.trace("graphqlContextFunction User not found"); return { authenticatedUser: null, + effectiveCommitteeRoles: [], userData: { auth: defaultAuthorization, authSource: AuthSource.None, diff --git a/schema.graphql b/schema.graphql index c4a34460..0365448e 100644 --- a/schema.graphql +++ b/schema.graphql @@ -56,6 +56,39 @@ enum AuthSource { None } +"""The identifier for a committee""" +enum CommitteeIdentifier { + communityDevelopmentCommittee + corporateCommittee + dancerRelationsCommittee + familyRelationsCommittee + fundraisingCommittee + marketingCommittee + miniMarathonsCommittee + operationsCommittee + overallCommittee + programmingCommittee + techCommittee + viceCommittee +} + +type CommitteeMembershipNode implements Node { + createdAt: DateTimeISO + id: ID! + person: PersonNode! + position: MembershipPositionType! + role: CommitteeRole! + team: TeamNode! + updatedAt: DateTimeISO +} + +"""Roles within a committee""" +enum CommitteeRole { + Chair + Coordinator + Member +} + type ConfigurationNode implements Node { createdAt: DateTimeISO id: ID! @@ -311,6 +344,11 @@ enum DeviceResolverStringFilterKeys { expoPushToken } +type EffectiveCommitteeRole { + committee: CommitteeIdentifier! + role: CommitteeRole! +} + """ A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. """ @@ -724,7 +762,9 @@ type ListTeamsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraph type LoginState { authSource: AuthSource! dbRole: DbRole! + effectiveCommitteeRoles: [EffectiveCommitteeRole!]! loggedIn: Boolean! + person: PersonNode } type MarathonHourNode implements Node { @@ -739,12 +779,24 @@ type MarathonHourNode implements Node { } type MarathonNode implements Node { + communityDevelopmentCommitteeTeam: TeamNode! + corporateCommitteeTeam: TeamNode! createdAt: DateTimeISO + dancerRelationsCommitteeTeam: TeamNode! endDate: DateTimeISO + familyRelationsCommitteeTeam: TeamNode! + fundraisingCommitteeTeam: TeamNode! hours: [MarathonHourNode!]! id: ID! + marketingCommitteeTeam: TeamNode! + miniMarathonsCommitteeTeam: TeamNode! + operationsCommitteeTeam: TeamNode! + overallCommitteeTeam: TeamNode! + programmingCommitteeTeam: TeamNode! startDate: DateTimeISO + techCommitteeTeam: TeamNode! updatedAt: DateTimeISO + viceCommitteeTeam: TeamNode! year: String! } @@ -1047,7 +1099,6 @@ enum NumericComparator { } type PersonNode implements Node { - captaincies: [MembershipNode!]! @deprecated(reason: "Use teams instead and filter by position") committees: [MembershipNode!]! createdAt: DateTimeISO dbRole: DbRole! @@ -1055,6 +1106,7 @@ type PersonNode implements Node { id: ID! linkblue: String name: String + primaryCommittee: CommitteeMembershipNode! teams: [MembershipNode!]! updatedAt: DateTimeISO } From f65318ce0730cad80720f7e5af70b1ec2e5dc0d1 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 21:19:27 +0000 Subject: [PATCH 049/153] Add support for retrieving committee memberships of a person --- .../repositories/person/PersonRepository.ts | 42 +++++++++++++- .../server/src/resolvers/PersonResolver.ts | 58 ++++++++++++++++--- schema.graphql | 1 + 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 62348b39..1d35261b 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -258,6 +258,30 @@ export class PersonRepository { }); } + async findCommitteeMembershipsOfPerson(param: UniquePersonParam) { + const rows = await this.prisma.person.findUnique({ + where: param, + select: { + memberships: { + where: { + team: { + type: TeamType.Committee, + }, + }, + include: { + team: { + select: { + correspondingCommittee: true, + }, + }, + }, + }, + }, + }); + + return rows?.memberships ?? null; + } + async findMembershipsOfPerson( param: UniquePersonParam, opts: @@ -267,13 +291,27 @@ export class PersonRepository { | { committeeRole: CommitteeRole; } - | Record = {} + | Record = {}, + types: TeamType[] | undefined = undefined ) { const rows = await this.prisma.person.findUnique({ where: param, select: { memberships: { - where: opts, + where: { + AND: [ + opts, + types + ? { + team: { + type: { + in: types, + }, + }, + } + : {}, + ], + }, }, }, }); diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 762d433d..cc2a0d09 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -1,3 +1,4 @@ +import { TeamType } from "@prisma/client"; import { AccessControl, AccessLevel, @@ -348,16 +349,25 @@ export class PersonResolver { } ) @FieldResolver(() => [MembershipNode]) - async committees(@Root() person: PersonNode): Promise { - const models = await this.personRepository.findMembershipsOfPerson({ - uuid: person.id, - }); + async committees( + @Root() person: PersonNode + ): Promise { + const models = await this.personRepository.findCommitteeMembershipsOfPerson( + { + uuid: person.id, + } + ); if (models == null) { return []; } - return models.map((row) => membershipModelToResource(row)); + return models.map((row) => + committeeMembershipModelToResource( + row, + row.team.correspondingCommittee!.identifier + ) + ); } @AccessControl( @@ -373,9 +383,41 @@ export class PersonResolver { ) @FieldResolver(() => [MembershipNode]) async teams(@Root() person: PersonNode): Promise { - const models = await this.personRepository.findMembershipsOfPerson({ - uuid: person.id, - }); + const models = await this.personRepository.findMembershipsOfPerson( + { + uuid: person.id, + }, + {}, + [TeamType.Spirit] + ); + + if (models == null) { + return []; + } + + return models.map((row) => membershipModelToResource(row)); + } + + @AccessControl( + { accessLevel: AccessLevel.Committee }, + { + rootMatch: [ + { + root: "uuid", + extractor: (userData) => userData.userId, + }, + ], + } + ) + @FieldResolver(() => [MembershipNode]) + async moraleTeams(@Root() person: PersonNode): Promise { + const models = await this.personRepository.findMembershipsOfPerson( + { + uuid: person.id, + }, + {}, + [TeamType.Morale] + ); if (models == null) { return []; diff --git a/schema.graphql b/schema.graphql index 0365448e..cc75718b 100644 --- a/schema.graphql +++ b/schema.graphql @@ -75,6 +75,7 @@ enum CommitteeIdentifier { type CommitteeMembershipNode implements Node { createdAt: DateTimeISO id: ID! + identifier: CommitteeIdentifier! person: PersonNode! position: MembershipPositionType! role: CommitteeRole! From d4b881a330d644a989857de4beb114afb5686687 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 21:19:34 +0000 Subject: [PATCH 050/153] Update Luxon imports and interval handling in event-related files --- packages/common/lib/client-parsers/event.ts | 8 +++++--- packages/portal/src/pages/config/useConfig.ts | 5 +++-- .../pages/events/create-event/useEventCreatorForm.ts | 5 ++++- .../single-event/edit-event/useEventEditorForm.ts | 10 +++++++--- .../events/single-event/view-event/EventViewer.tsx | 10 +++++++--- .../src/pages/marathon/single/view/MarathonViewer.tsx | 4 ++-- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/common/lib/client-parsers/event.ts b/packages/common/lib/client-parsers/event.ts index 22e55fe4..577f9f16 100644 --- a/packages/common/lib/client-parsers/event.ts +++ b/packages/common/lib/client-parsers/event.ts @@ -1,8 +1,10 @@ -import { Interval } from "luxon"; +import type { Interval } from "luxon"; + +import { intervalFromSomething } from "../utility/time/intervalTools.js"; interface EventOccurrence { fullDay: boolean; - interval: string; + interval: { readonly start: Date | string; readonly end: Date | string }; } interface ParsedEventOccurrence { @@ -15,7 +17,7 @@ export function parseEventOccurrence( ): ParsedEventOccurrence { return { fullDay: occurrence.fullDay, - interval: Interval.fromISO(occurrence.interval), + interval: intervalFromSomething(occurrence.interval), }; } diff --git a/packages/portal/src/pages/config/useConfig.ts b/packages/portal/src/pages/config/useConfig.ts index 2138bd97..2d6fec94 100644 --- a/packages/portal/src/pages/config/useConfig.ts +++ b/packages/portal/src/pages/config/useConfig.ts @@ -1,4 +1,5 @@ import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; +import { dateTimeFromSomething } from "@ukdanceblue/common"; import { getFragmentData, graphql, @@ -78,10 +79,10 @@ export function useConfig(): { const configValue = { value: config.value, validAfter: config.validAfter - ? DateTime.fromISO(config.validAfter) + ? dateTimeFromSomething(config.validAfter) : null, validUntil: config.validUntil - ? DateTime.fromISO(config.validUntil) + ? dateTimeFromSomething(config.validUntil) : null, createdAt: config.createdAt ? typeof config.createdAt === "string" diff --git a/packages/portal/src/pages/events/create-event/useEventCreatorForm.ts b/packages/portal/src/pages/events/create-event/useEventCreatorForm.ts index 76a0d544..05f0c7db 100644 --- a/packages/portal/src/pages/events/create-event/useEventCreatorForm.ts +++ b/packages/portal/src/pages/events/create-event/useEventCreatorForm.ts @@ -47,7 +47,10 @@ export function useEventCreatorForm() { const retVal: Parameters< typeof createEvent >[0]["input"]["occurrences"][number] = { - interval: occurrence.interval.toISO(), + interval: { + start: occurrence.interval.start!.toISO(), + end: occurrence.interval.end!.toISO(), + }, fullDay: occurrence.fullDay, }; return retVal; diff --git a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts index 6d2b67aa..243bbde3 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts +++ b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts @@ -1,12 +1,13 @@ import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; import { useForm } from "@tanstack/react-form"; +import { intervalFromSomething } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData } from "@ukdanceblue/common/graphql-client-admin"; import type { SetEventInput, SetEventOccurrenceInput, } from "@ukdanceblue/common/graphql-client-admin/raw-types"; -import { Interval } from "luxon"; +import type { Interval } from "luxon"; import type { UseQueryExecute } from "urql"; import { useMutation } from "urql"; @@ -43,7 +44,7 @@ export function useEventEditorForm( occurrences: eventData?.occurrences.map((occurrence) => ({ uuid: occurrence.uuid, - interval: Interval.fromISO(occurrence.interval), + interval: intervalFromSomething(occurrence.interval), fullDay: occurrence.fullDay, })) ?? [], }, @@ -63,7 +64,10 @@ export function useEventEditorForm( let retVal: Parameters< typeof setEvent >[0]["input"]["occurrences"][number] = { - interval: occurrence.interval.toISO(), + interval: { + start: occurrence.interval.start!.toISO(), + end: occurrence.interval.end!.toISO(), + }, fullDay: occurrence.fullDay, }; if (occurrence.uuid) { diff --git a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx index 2094873b..d981914e 100644 --- a/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx +++ b/packages/portal/src/pages/events/single-event/view-event/EventViewer.tsx @@ -1,6 +1,9 @@ import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; import { Link, useNavigate } from "@tanstack/react-router"; -import { base64StringToArray } from "@ukdanceblue/common"; +import { + base64StringToArray, + intervalFromSomething, +} from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData, @@ -8,7 +11,8 @@ import { } from "@ukdanceblue/common/graphql-client-admin"; import { Button, Descriptions, Flex, Image, List, Typography } from "antd"; import DescriptionsItem from "antd/es/descriptions/Item"; -import { DateTime, Interval } from "luxon"; +import type { Interval } from "luxon"; +import { DateTime } from "luxon"; import { useMemo } from "react"; import { thumbHashToDataURL } from "thumbhash"; @@ -53,7 +57,7 @@ export function EventViewer({ () => eventData?.occurrences ? eventData.occurrences.map((occurrence) => { - const interval = Interval.fromISO(occurrence.interval); + const interval = intervalFromSomething(occurrence.interval); return { interval, fullDay: occurrence.fullDay, diff --git a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx index 4cc073ce..c30b70dd 100644 --- a/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx +++ b/packages/portal/src/pages/marathon/single/view/MarathonViewer.tsx @@ -46,12 +46,12 @@ export const MarathonViewer = ({ {marathonData.year} - {dateTimeFromSomething(marathonData.startDate).toLocaleString( + {dateTimeFromSomething(marathonData.startDate)?.toLocaleString( DateTime.DATETIME_MED )} - {dateTimeFromSomething(marathonData.endDate).toLocaleString( + {dateTimeFromSomething(marathonData.endDate)?.toLocaleString( DateTime.DATETIME_MED )} From 0bc7343de7d452dcceef026069bdd2a6c37ff315 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 21:20:36 +0000 Subject: [PATCH 051/153] Update PersonResolver to use CommitteeMembershipNode for committees field --- packages/server/src/resolvers/PersonResolver.ts | 2 +- schema.graphql | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index cc2a0d09..f5910dbb 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -348,7 +348,7 @@ export class PersonResolver { ], } ) - @FieldResolver(() => [MembershipNode]) + @FieldResolver(() => [CommitteeMembershipNode]) async committees( @Root() person: PersonNode ): Promise { diff --git a/schema.graphql b/schema.graphql index cc75718b..86df54b2 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1100,12 +1100,13 @@ enum NumericComparator { } type PersonNode implements Node { - committees: [MembershipNode!]! + committees: [CommitteeMembershipNode!]! createdAt: DateTimeISO dbRole: DbRole! email: String! id: ID! linkblue: String + moraleTeams: [MembershipNode!]! name: String primaryCommittee: CommitteeMembershipNode! teams: [MembershipNode!]! From 76d324a6aee905442253f69cc4b08ee40db4d428 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 24 May 2024 21:34:20 +0000 Subject: [PATCH 052/153] Update code to use marathon.year instead of marathonYear in team forms --- .../common/lib/graphql-client-admin/gql.ts | 8 +- .../lib/graphql-client-admin/graphql.ts | 77 ++++++++++++++++--- .../lib/graphql-client-public/graphql.ts | 65 ++++++++++++++-- .../person/create/usePersonCreatorForm.ts | 15 ---- .../forms/person/edit/usePersonEditorForm.ts | 20 +---- .../forms/team/create/useTeamCreatorForm.ts | 4 - .../forms/team/edit/useTeamEditorForm.ts | 3 +- .../src/elements/tables/PeopleTable.tsx | 10 ++- .../tables/point-entry/PointEntryTable.tsx | 4 +- .../elements/viewers/person/PersonViewer.tsx | 24 +++--- .../server/src/resolvers/PersonResolver.ts | 5 +- packages/server/src/resolvers/TeamResolver.ts | 3 - schema.graphql | 4 +- 13 files changed, 152 insertions(+), 90 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 8d88b7cb..a2628f92 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -35,7 +35,7 @@ const documents = { "\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n": types.TeamCreatorDocument, "\n fragment TeamEditorFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n type\n }\n": types.TeamEditorFragmentFragmentDoc, "\n mutation TeamEditor($uuid: String!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.TeamEditorDocument, - "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n": types.PeopleTableFragmentFragmentDoc, + "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n primaryCommittee {\n identifier\n role\n }\n }\n": types.PeopleTableFragmentFragmentDoc, "\n query PeopleTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [PersonResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [PersonResolverKeyedOneOfFilterItem!]\n $stringFilters: [PersonResolverKeyedStringFilterItem!]\n ) {\n listPeople(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...PeopleTableFragment\n }\n }\n }\n": types.PeopleTableDocument, "\n query TeamsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [TeamResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [TeamResolverKeyedOneOfFilterItem!]\n $stringFilters: [TeamResolverKeyedStringFilterItem!]\n ) {\n teams(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...TeamsTableFragment\n }\n }\n }\n": types.TeamsTableDocument, "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n": types.TeamsTableFragmentFragmentDoc, @@ -46,7 +46,7 @@ const documents = { "\n mutation DeletePointEntry($uuid: String!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePointEntryDocument, "\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n": types.PointEntryTableFragmentFragmentDoc, "\n mutation DeletePerson($uuid: String!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePersonDocument, - "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n": types.PersonViewerFragmentFragmentDoc, + "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n": types.PersonViewerFragmentFragmentDoc, "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n": types.LoginStateDocument, @@ -192,7 +192,7 @@ export function graphql(source: "\n mutation TeamEditor($uuid: String!, $input: /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n"): (typeof documents)["\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n }\n"]; +export function graphql(source: "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n primaryCommittee {\n identifier\n role\n }\n }\n"): (typeof documents)["\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n primaryCommittee {\n identifier\n role\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -236,7 +236,7 @@ export function graphql(source: "\n mutation DeletePerson($uuid: String!) {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n"): (typeof documents)["\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 830487fb..1ae9d688 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -83,6 +83,43 @@ export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRespo export { AuthSource }; +/** The identifier for a committee */ +export const CommitteeIdentifier = { + CommunityDevelopmentCommittee: 'communityDevelopmentCommittee', + CorporateCommittee: 'corporateCommittee', + DancerRelationsCommittee: 'dancerRelationsCommittee', + FamilyRelationsCommittee: 'familyRelationsCommittee', + FundraisingCommittee: 'fundraisingCommittee', + MarketingCommittee: 'marketingCommittee', + MiniMarathonsCommittee: 'miniMarathonsCommittee', + OperationsCommittee: 'operationsCommittee', + OverallCommittee: 'overallCommittee', + ProgrammingCommittee: 'programmingCommittee', + TechCommittee: 'techCommittee', + ViceCommittee: 'viceCommittee' +} as const; + +export type CommitteeIdentifier = typeof CommitteeIdentifier[keyof typeof CommitteeIdentifier]; +export type CommitteeMembershipNode = Node & { + readonly __typename?: 'CommitteeMembershipNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly identifier: CommitteeIdentifier; + readonly person: PersonNode; + readonly position: MembershipPositionType; + readonly role: CommitteeRole; + readonly team: TeamNode; + readonly updatedAt?: Maybe; +}; + +/** Roles within a committee */ +export const CommitteeRole = { + Chair: 'Chair', + Coordinator: 'Coordinator', + Member: 'Member' +} as const; + +export type CommitteeRole = typeof CommitteeRole[keyof typeof CommitteeRole]; export type ConfigurationNode = Node & { readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; @@ -199,7 +236,6 @@ export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & Ab export type CreateTeamInput = { readonly legacyStatus: TeamLegacyStatus; - readonly marathonYear: Scalars['String']['input']; readonly name: Scalars['String']['input']; readonly persistentIdentifier?: InputMaybe; readonly type: TeamType; @@ -332,6 +368,12 @@ export const DeviceResolverStringFilterKeys = { } as const; export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; +export type EffectiveCommitteeRole = { + readonly __typename?: 'EffectiveCommitteeRole'; + readonly committee: CommitteeIdentifier; + readonly role: CommitteeRole; +}; + export type EventNode = Node & { readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; @@ -711,7 +753,9 @@ export type LoginState = { readonly __typename?: 'LoginState'; readonly authSource: AuthSource; readonly dbRole: DbRole; + readonly effectiveCommitteeRoles: ReadonlyArray; readonly loggedIn: Scalars['Boolean']['output']; + readonly person?: Maybe; }; export type MarathonHourNode = Node & { @@ -728,12 +772,24 @@ export type MarathonHourNode = Node & { export type MarathonNode = Node & { readonly __typename?: 'MarathonNode'; + readonly communityDevelopmentCommitteeTeam: TeamNode; + readonly corporateCommitteeTeam: TeamNode; readonly createdAt?: Maybe; + readonly dancerRelationsCommitteeTeam: TeamNode; readonly endDate?: Maybe; + readonly familyRelationsCommitteeTeam: TeamNode; + readonly fundraisingCommitteeTeam: TeamNode; readonly hours: ReadonlyArray; readonly id: Scalars['ID']['output']; + readonly marketingCommitteeTeam: TeamNode; + readonly miniMarathonsCommitteeTeam: TeamNode; + readonly operationsCommitteeTeam: TeamNode; + readonly overallCommitteeTeam: TeamNode; + readonly programmingCommitteeTeam: TeamNode; readonly startDate?: Maybe; + readonly techCommitteeTeam: TeamNode; readonly updatedAt?: Maybe; + readonly viceCommitteeTeam: TeamNode; readonly year: Scalars['String']['output']; }; @@ -1238,15 +1294,15 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; - /** @deprecated Use teams instead and filter by position */ - readonly captaincies: ReadonlyArray; - readonly committees: ReadonlyArray; + readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; readonly email: Scalars['String']['output']; readonly id: Scalars['ID']['output']; readonly linkblue?: Maybe; + readonly moraleTeams: ReadonlyArray; readonly name?: Maybe; + readonly primaryCommittee?: Maybe; readonly teams: ReadonlyArray; readonly updatedAt?: Maybe; }; @@ -1763,7 +1819,6 @@ export type SetMarathonInput = { export type SetPersonInput = { readonly captainOf?: InputMaybe>; - readonly dbRole?: InputMaybe; readonly email?: InputMaybe; readonly linkblue?: InputMaybe; readonly memberOf?: InputMaybe>; @@ -2017,7 +2072,7 @@ export type TeamEditorMutationVariables = Exact<{ export type TeamEditorMutation = { readonly __typename?: 'Mutation', readonly setTeam: { readonly __typename?: 'SingleTeamResponse', readonly ok: boolean } }; -export type PeopleTableFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole } & { ' $fragmentName'?: 'PeopleTableFragmentFragment' }; +export type PeopleTableFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly primaryCommittee?: { readonly __typename?: 'CommitteeMembershipNode', readonly identifier: CommitteeIdentifier, readonly role: CommitteeRole } | null } & { ' $fragmentName'?: 'PeopleTableFragmentFragment' }; export type PeopleTableQueryVariables = Exact<{ page?: InputMaybe; @@ -2106,7 +2161,7 @@ export type DeletePersonMutationVariables = Exact<{ export type DeletePersonMutation = { readonly __typename?: 'Mutation', readonly deletePerson: { readonly __typename?: 'DeletePersonResponse', readonly ok: boolean } }; -export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; +export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }>, readonly committees: ReadonlyArray<{ readonly __typename?: 'CommitteeMembershipNode', readonly identifier: CommitteeIdentifier, readonly role: CommitteeRole }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; export type DeleteTeamMutationVariables = Exact<{ uuid: Scalars['String']['input']; @@ -2401,12 +2456,12 @@ export const SingleNotificationFragmentFragmentDoc = {"kind":"Document","definit export const TeamNameFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; export const PersonEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const TeamEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const PeopleTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; +export const PeopleTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TeamsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveriesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; export const PointEntryTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; -export const PersonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const PersonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TeamViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}}]} as unknown as DocumentNode; export const ConfigFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const EventsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; @@ -2433,7 +2488,7 @@ export const PointEntryOpportunityLookupDocument = {"kind":"Document","definitio export const CreatePointOpportunityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointOpportunity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointOpportunityInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointOpportunity"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathon"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; +export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; @@ -2466,6 +2521,6 @@ export const NotificationManagerDocument = {"kind":"Document","definitions":[{"k export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index fbdbc55d..c479749f 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -83,6 +83,43 @@ export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRespo export { AuthSource }; +/** The identifier for a committee */ +export const CommitteeIdentifier = { + CommunityDevelopmentCommittee: 'communityDevelopmentCommittee', + CorporateCommittee: 'corporateCommittee', + DancerRelationsCommittee: 'dancerRelationsCommittee', + FamilyRelationsCommittee: 'familyRelationsCommittee', + FundraisingCommittee: 'fundraisingCommittee', + MarketingCommittee: 'marketingCommittee', + MiniMarathonsCommittee: 'miniMarathonsCommittee', + OperationsCommittee: 'operationsCommittee', + OverallCommittee: 'overallCommittee', + ProgrammingCommittee: 'programmingCommittee', + TechCommittee: 'techCommittee', + ViceCommittee: 'viceCommittee' +} as const; + +export type CommitteeIdentifier = typeof CommitteeIdentifier[keyof typeof CommitteeIdentifier]; +export type CommitteeMembershipNode = Node & { + readonly __typename?: 'CommitteeMembershipNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly identifier: CommitteeIdentifier; + readonly person: PersonNode; + readonly position: MembershipPositionType; + readonly role: CommitteeRole; + readonly team: TeamNode; + readonly updatedAt?: Maybe; +}; + +/** Roles within a committee */ +export const CommitteeRole = { + Chair: 'Chair', + Coordinator: 'Coordinator', + Member: 'Member' +} as const; + +export type CommitteeRole = typeof CommitteeRole[keyof typeof CommitteeRole]; export type ConfigurationNode = Node & { readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; @@ -199,7 +236,6 @@ export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & Ab export type CreateTeamInput = { readonly legacyStatus: TeamLegacyStatus; - readonly marathonYear: Scalars['String']['input']; readonly name: Scalars['String']['input']; readonly persistentIdentifier?: InputMaybe; readonly type: TeamType; @@ -332,6 +368,12 @@ export const DeviceResolverStringFilterKeys = { } as const; export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; +export type EffectiveCommitteeRole = { + readonly __typename?: 'EffectiveCommitteeRole'; + readonly committee: CommitteeIdentifier; + readonly role: CommitteeRole; +}; + export type EventNode = Node & { readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; @@ -711,7 +753,9 @@ export type LoginState = { readonly __typename?: 'LoginState'; readonly authSource: AuthSource; readonly dbRole: DbRole; + readonly effectiveCommitteeRoles: ReadonlyArray; readonly loggedIn: Scalars['Boolean']['output']; + readonly person?: Maybe; }; export type MarathonHourNode = Node & { @@ -728,12 +772,24 @@ export type MarathonHourNode = Node & { export type MarathonNode = Node & { readonly __typename?: 'MarathonNode'; + readonly communityDevelopmentCommitteeTeam: TeamNode; + readonly corporateCommitteeTeam: TeamNode; readonly createdAt?: Maybe; + readonly dancerRelationsCommitteeTeam: TeamNode; readonly endDate?: Maybe; + readonly familyRelationsCommitteeTeam: TeamNode; + readonly fundraisingCommitteeTeam: TeamNode; readonly hours: ReadonlyArray; readonly id: Scalars['ID']['output']; + readonly marketingCommitteeTeam: TeamNode; + readonly miniMarathonsCommitteeTeam: TeamNode; + readonly operationsCommitteeTeam: TeamNode; + readonly overallCommitteeTeam: TeamNode; + readonly programmingCommitteeTeam: TeamNode; readonly startDate?: Maybe; + readonly techCommitteeTeam: TeamNode; readonly updatedAt?: Maybe; + readonly viceCommitteeTeam: TeamNode; readonly year: Scalars['String']['output']; }; @@ -1238,15 +1294,15 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; - /** @deprecated Use teams instead and filter by position */ - readonly captaincies: ReadonlyArray; - readonly committees: ReadonlyArray; + readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; readonly email: Scalars['String']['output']; readonly id: Scalars['ID']['output']; readonly linkblue?: Maybe; + readonly moraleTeams: ReadonlyArray; readonly name?: Maybe; + readonly primaryCommittee?: Maybe; readonly teams: ReadonlyArray; readonly updatedAt?: Maybe; }; @@ -1763,7 +1819,6 @@ export type SetMarathonInput = { export type SetPersonInput = { readonly captainOf?: InputMaybe>; - readonly dbRole?: InputMaybe; readonly email?: InputMaybe; readonly linkblue?: InputMaybe; readonly memberOf?: InputMaybe>; diff --git a/packages/portal/src/elements/forms/person/create/usePersonCreatorForm.ts b/packages/portal/src/elements/forms/person/create/usePersonCreatorForm.ts index 759b46be..c4d1bbf4 100644 --- a/packages/portal/src/elements/forms/person/create/usePersonCreatorForm.ts +++ b/packages/portal/src/elements/forms/person/create/usePersonCreatorForm.ts @@ -1,6 +1,5 @@ import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; import { useForm } from "@tanstack/react-form"; -import { DbRole } from "@ukdanceblue/common"; import type { DocumentType } from "@ukdanceblue/common/graphql-client-admin"; import { type CreatePersonInput } from "@ukdanceblue/common/graphql-client-admin/raw-types"; import { useMutation } from "urql"; @@ -31,11 +30,6 @@ export function usePersonCreatorForm( name: "", linkblue: "", email: "", - role: { - dbRole: DbRole.None, - committeeRole: null, - committeeIdentifier: null, - }, captainOf: [], memberOf: [], }, @@ -66,10 +60,6 @@ export function usePersonCreatorForm( } } - if (values.role?.committeeIdentifier && !values.role.committeeRole) { - return "Committee role is required if a committee is selected"; - } - return undefined; }, onSubmit: async (values) => { @@ -82,11 +72,6 @@ export function usePersonCreatorForm( name: values.name || null, linkblue: values.linkblue || null, email: values.email, - role: { - dbRole: values.role?.dbRole ?? DbRole.None, - committeeRole: values.role?.committeeRole ?? null, - committeeIdentifier: values.role?.committeeIdentifier ?? null, - }, captainOf: values.captainOf ?? [], memberOf: values.memberOf ?? [], }, diff --git a/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts b/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts index bb8100b5..28ee85bb 100644 --- a/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts +++ b/packages/portal/src/elements/forms/person/edit/usePersonEditorForm.ts @@ -1,6 +1,6 @@ import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; import { useForm } from "@tanstack/react-form"; -import { DbRole, MembershipPositionType } from "@ukdanceblue/common"; +import { MembershipPositionType } from "@ukdanceblue/common"; import type { DocumentType, FragmentType, @@ -34,11 +34,6 @@ export function usePersonEditorForm( name: personData?.name ?? "", linkblue: personData?.linkblue ?? "", email: personData?.email ?? "", - role: { - dbRole: DbRole.None, - committeeRole: personData?.role.committeeRole ?? null, - committeeIdentifier: personData?.role.committeeIdentifier ?? null, - }, captainOf: personData?.teams .filter( @@ -81,10 +76,6 @@ export function usePersonEditorForm( } } - if (values.role?.committeeIdentifier && !values.role.committeeRole) { - return "Committee role is required if a committee is selected"; - } - return undefined; }, onSubmit: async (values) => { @@ -96,21 +87,12 @@ export function usePersonEditorForm( throw new Error("Email is required"); } - // TODO: This is actually ignored on the server, we need to find a way to - // remove it here - const dbRole: DbRole = DbRole.None; - const { data } = await setPerson({ uuid: personData.id, input: { name: values.name || null, linkblue: values.linkblue || null, email: values.email, - role: { - dbRole, - committeeRole: values.role?.committeeRole ?? null, - committeeIdentifier: values.role?.committeeIdentifier ?? null, - }, captainOf: values.captainOf ?? [], memberOf: values.memberOf ?? [], }, diff --git a/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts b/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts index 1101b83d..47177646 100644 --- a/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts +++ b/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts @@ -26,7 +26,6 @@ export function useTeamCreatorForm( defaultValues: { name: "", legacyStatus: TeamLegacyStatus.NewTeam, - marathonYear: "DB24", persistentIdentifier: null, type: TeamType.Spirit, }, @@ -35,9 +34,6 @@ export function useTeamCreatorForm( input: { name: values.name, legacyStatus: values.legacyStatus, - // TODO: Make this dynamic - marathonYear: "DB24", - persistentIdentifier: values.persistentIdentifier ?? null, type: values.type, }, }); diff --git a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts index 71051c24..c924906f 100644 --- a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts +++ b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts @@ -34,8 +34,7 @@ export function useTeamEditorForm( name: teamData?.name ?? "", legacyStatus: teamData?.legacyStatus ?? null, // TODO: Make this dynamic - marathonYear: teamData?.marathonYear ?? "DB24", - persistentIdentifier: teamData?.persistentIdentifier ?? null, + marathonYear: teamData?.marathon.year ?? "DB24", type: teamData?.type ?? TeamType.Spirit, }, onSubmit: async (values) => { diff --git a/packages/portal/src/elements/tables/PeopleTable.tsx b/packages/portal/src/elements/tables/PeopleTable.tsx index 4af019a3..abe966ba 100644 --- a/packages/portal/src/elements/tables/PeopleTable.tsx +++ b/packages/portal/src/elements/tables/PeopleTable.tsx @@ -25,6 +25,10 @@ const PeopleTableFragment = graphql(/* GraphQL */ ` linkblue email dbRole + primaryCommittee { + identifier + role + } } `); @@ -229,7 +233,7 @@ export const PeopleTable = () => { dataIndex: "committeeRole", render: (_, record) => { // TODO: fix - return record.role.committeeRole ?? "None"; + return record.primaryCommittee?.role ?? "None"; }, sorter: true, sortDirections: ["ascend", "descend"], @@ -243,8 +247,8 @@ export const PeopleTable = () => { dataIndex: "committeeName", render: (_, record) => { // TODO: fix - return record.role.committeeIdentifier - ? committeeNames[record.role.committeeIdentifier] + return record.primaryCommittee?.identifier + ? committeeNames[record.primaryCommittee.identifier] : "None"; }, sorter: true, diff --git a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx index 6577a5a9..bb4a8590 100644 --- a/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx +++ b/packages/portal/src/elements/tables/point-entry/PointEntryTable.tsx @@ -1,11 +1,11 @@ import { DeleteOutlined } from "@ant-design/icons"; +import { dateTimeFromSomething } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData, graphql, } from "@ukdanceblue/common/graphql-client-admin"; import { Button, Table } from "antd"; -import { DateTime } from "luxon"; import type { UseQueryExecute } from "urql"; import { usePointEntryDeletePopup } from "./PointEntryDeletePopup"; @@ -86,7 +86,7 @@ export function PointEntryTable({ const { name, opportunityDate } = record.pointOpportunity; let str = name; if (opportunityDate) { - str += ` (${DateTime.fromISO(opportunityDate).toFormat( + str += ` (${dateTimeFromSomething(opportunityDate).toFormat( "yyyy-MM-dd" )})`; } diff --git a/packages/portal/src/elements/viewers/person/PersonViewer.tsx b/packages/portal/src/elements/viewers/person/PersonViewer.tsx index 4961a5e4..db036720 100644 --- a/packages/portal/src/elements/viewers/person/PersonViewer.tsx +++ b/packages/portal/src/elements/viewers/person/PersonViewer.tsx @@ -24,6 +24,10 @@ export const PersonViewerFragment = graphql(/* GraphQL */ ` name } } + committees { + identifier + role + } } `); @@ -84,22 +88,12 @@ export function PersonViewer({ }, { label: "Role", - children: stringifyDbRole(personData.role.dbRole), + children: stringifyDbRole(personData.dbRole), }, - ...(personData.role.committeeRole - ? [ - { - label: "Committee", - children: personData.role.committeeIdentifier - ? committeeNames[personData.role.committeeIdentifier] - : "N/A", - }, - { - label: "Committee Position", - children: personData.role.committeeRole, - }, - ] - : []), + ...personData.committees.map((committee) => ({ + label: committeeNames[committee.identifier], + children: stringifyDbRole(committee.role), + })), { label: "Teams", children: diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index f5910dbb..8b568bc9 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -137,9 +137,6 @@ class SetPersonInput { @Field(() => String, { nullable: true }) linkblue?: string; - @Field(() => DbRole, { nullable: true }) - dbRole?: DbRole; - @Field(() => [String], { nullable: true }) memberOf?: string[]; @@ -437,7 +434,7 @@ export class PersonResolver { ], } ) - @FieldResolver(() => CommitteeMembershipNode) + @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) async primaryCommittee( @Root() person: PersonNode ): Promise { diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index a3d30621..f78923de 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -86,9 +86,6 @@ class CreateTeamInput implements OptionalToNullable> { @Field(() => TeamLegacyStatus) legacyStatus!: TeamLegacyStatus; - @Field(() => String) - marathonYear!: Common.MarathonYearString; - @Field(() => String, { nullable: true }) persistentIdentifier!: string | null; } diff --git a/schema.graphql b/schema.graphql index 86df54b2..82d49e54 100644 --- a/schema.graphql +++ b/schema.graphql @@ -200,7 +200,6 @@ type CreatePointOpportunityResponse implements AbstractGraphQLCreatedResponse & input CreateTeamInput { legacyStatus: TeamLegacyStatus! - marathonYear: String! name: String! persistentIdentifier: String type: TeamType! @@ -1108,7 +1107,7 @@ type PersonNode implements Node { linkblue: String moraleTeams: [MembershipNode!]! name: String - primaryCommittee: CommitteeMembershipNode! + primaryCommittee: CommitteeMembershipNode teams: [MembershipNode!]! updatedAt: DateTimeISO } @@ -1833,7 +1832,6 @@ input SetMarathonInput { input SetPersonInput { captainOf: [String!] - dbRole: DbRole email: EmailAddress linkblue: String memberOf: [String!] From 88ffbeb2e213b9b1d6eaf0628fbc014fd95a9c57 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 19:17:26 +0000 Subject: [PATCH 053/153] Refactor team creation form to remove persistentIdentifier field --- .../lib/graphql-client-admin/graphql.ts | 1 - .../common/lib/graphql-client-public/gql.ts | 4 ++-- .../lib/graphql-client-public/graphql.ts | 7 +++--- .../root/ProfileScreen/ProfileScreen.tsx | 22 ++++++++++--------- .../forms/team/create/TeamCreator.tsx | 6 ----- .../forms/team/create/useTeamCreatorForm.ts | 1 - .../src/repositories/team/TeamRepository.ts | 1 - packages/server/src/resolvers/TeamResolver.ts | 4 ---- schema.graphql | 1 - 9 files changed, 17 insertions(+), 30 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 1ae9d688..2416e8d3 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -237,7 +237,6 @@ export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & Ab export type CreateTeamInput = { readonly legacyStatus: TeamLegacyStatus; readonly name: Scalars['String']['input']; - readonly persistentIdentifier?: InputMaybe; readonly type: TeamType; }; diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index 19f2d404..cba15fe4 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -27,7 +27,7 @@ const documents = { "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, "\n query DeviceNotifications(\n $deviceUuid: String!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n": types.DeviceNotificationsDocument, "\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n": types.ProfileScreenAuthFragmentFragmentDoc, - "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, + "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n": types.RootScreenDocumentDocument, "\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n": types.RootScreenAuthFragmentFragmentDoc, "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, @@ -114,7 +114,7 @@ export function graphql(source: "\n fragment ProfileScreenAuthFragment on Login /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"): (typeof documents)["\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n }\n"]; +export function graphql(source: "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n"): (typeof documents)["\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index c479749f..293f414c 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -237,7 +237,6 @@ export type CreatePointOpportunityResponse = AbstractGraphQlCreatedResponse & Ab export type CreateTeamInput = { readonly legacyStatus: TeamLegacyStatus; readonly name: Scalars['String']['input']; - readonly persistentIdentifier?: InputMaybe; readonly type: TeamType; }; @@ -2002,7 +2001,7 @@ export type DeviceNotificationsQuery = { readonly __typename?: 'Query', readonly export type ProfileScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly dbRole: DbRole, readonly authSource: AuthSource } & { ' $fragmentName'?: 'ProfileScreenAuthFragmentFragment' }; -export type ProfileScreenUserFragmentFragment = { readonly __typename?: 'PersonNode', readonly name?: string | null, readonly linkblue?: string | null, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly name: string } }> } & { ' $fragmentName'?: 'ProfileScreenUserFragmentFragment' }; +export type ProfileScreenUserFragmentFragment = { readonly __typename?: 'PersonNode', readonly name?: string | null, readonly linkblue?: string | null, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly name: string } }>, readonly primaryCommittee?: { readonly __typename?: 'CommitteeMembershipNode', readonly identifier: CommitteeIdentifier, readonly role: CommitteeRole } | null } & { ' $fragmentName'?: 'ProfileScreenUserFragmentFragment' }; export type RootScreenDocumentQueryVariables = Exact<{ [key: string]: never; }>; @@ -2079,7 +2078,7 @@ export const NotificationFragmentFragmentDoc = {"kind":"Document","definitions": export const NotificationDeliveryFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; export const EventScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ProfileScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]} as unknown as DocumentNode; -export const ProfileScreenUserFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ProfileScreenUserFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const RootScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; export const ImageViewFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; export const HourScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]} as unknown as DocumentNode; @@ -2093,7 +2092,7 @@ export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"Op export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; export const SetDeviceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDevice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterDeviceInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerDevice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; -export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; +export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"ASCENDING"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx index 006749ba..702d79a7 100644 --- a/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx +++ b/packages/mobile/src/navigation/root/ProfileScreen/ProfileScreen.tsx @@ -46,6 +46,10 @@ export const ProfileScreenUserFragment = graphql(/* GraphQL */ ` name } } + primaryCommittee { + identifier + role + } } `); @@ -90,24 +94,22 @@ const ProfileScreen = ({ } const committeeString = useMemo(() => { - if (authData?.dbRole === DbRole.Committee) { + if (userData?.primaryCommittee) { if ( // TODO: Add a way to query committee info - authData.role.committeeIdentifier === - CommitteeIdentifier.viceCommittee && - authData.role.committeeRole === CommitteeRole.Chair + userData.primaryCommittee.identifier === + CommitteeIdentifier.overallCommittee && + userData.primaryCommittee.role === CommitteeRole.Chair ) { return "✨ Overall Chair ✨"; } return `Committee: ${ - authData.role.committeeIdentifier - ? committeeNames[authData.role.committeeIdentifier] - : "Unknown" - } ${authData.role.committeeRole}`; + committeeNames[userData.primaryCommittee.identifier] + } ${userData.primaryCommittee.role}`; } else { return null; } - }, [authData]); + }, [userData?.primaryCommittee]); if (loading) { return ( @@ -115,7 +117,7 @@ const ProfileScreen = ({ ); - } else if (authData?.role.dbRole !== DbRole.None) { + } else if (authData?.dbRole !== DbRole.None) { return ( <> diff --git a/packages/portal/src/elements/forms/team/create/TeamCreator.tsx b/packages/portal/src/elements/forms/team/create/TeamCreator.tsx index 8ac9e03f..ccc14b79 100644 --- a/packages/portal/src/elements/forms/team/create/TeamCreator.tsx +++ b/packages/portal/src/elements/forms/team/create/TeamCreator.tsx @@ -86,12 +86,6 @@ export function TeamCreator() { /> )} - {formApi.getFieldValue("persistentIdentifier") ? ( -

    - Special Identifier:{" "} - {formApi.getFieldValue("persistentIdentifier")} -

    - ) : null} {(field) => ( { diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index 399a5022..3b9377ce 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -218,7 +218,6 @@ export class TeamRepository { name: string; type: TeamType; legacyStatus: TeamLegacyStatus; - persistentIdentifier?: string | null | undefined; }, marathon: UniqueMarathonParam ) { diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index f78923de..b4abcf93 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -85,9 +85,6 @@ class CreateTeamInput implements OptionalToNullable> { @Field(() => TeamLegacyStatus) legacyStatus!: TeamLegacyStatus; - - @Field(() => String, { nullable: true }) - persistentIdentifier!: string | null; } @InputType() @@ -226,7 +223,6 @@ export class TeamResolver { name: input.name, type: input.type, legacyStatus: input.legacyStatus, - persistentIdentifier: input.persistentIdentifier, }, { uuid: marathonUuid } ); diff --git a/schema.graphql b/schema.graphql index 82d49e54..6d798c84 100644 --- a/schema.graphql +++ b/schema.graphql @@ -201,7 +201,6 @@ type CreatePointOpportunityResponse implements AbstractGraphQLCreatedResponse & input CreateTeamInput { legacyStatus: TeamLegacyStatus! name: String! - persistentIdentifier: String type: TeamType! } From b4dbea033a45e0104cee56f5f07c09f058c6b704 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 20:12:51 +0000 Subject: [PATCH 054/153] Update logic around auth --- .../lib/api/resources/authorization.test.ts | 20 ---- packages/common/lib/authentication/jwt.ts | 34 +------ .../common/lib/authorization/accessControl.ts | 63 ++++++++---- .../common/lib/graphql-client-admin/gql.ts | 4 +- .../lib/graphql-client-admin/graphql.ts | 4 +- packages/server/src/lib/auth/index.ts | 97 +------------------ packages/server/src/resolvers/LoginState.ts | 2 +- packages/server/src/resolvers/context.ts | 63 +++++++++--- 8 files changed, 104 insertions(+), 183 deletions(-) diff --git a/packages/common/lib/api/resources/authorization.test.ts b/packages/common/lib/api/resources/authorization.test.ts index 2cd79f4e..e865effa 100644 --- a/packages/common/lib/api/resources/authorization.test.ts +++ b/packages/common/lib/api/resources/authorization.test.ts @@ -275,25 +275,6 @@ describe("checkAuthorization", () => { ).toBe(false); }); - it("should work with exact committeeRole matching", () => { - expect( - checkAuthorization( - { - committeeRole: CommitteeRole.Chair, - }, - techChair - ) - ).toBe(true); - expect( - checkAuthorization( - { - committeeRole: CommitteeRole.Chair, - }, - none - ) - ).toBe(false); - }); - it("should work with minimum dbRole matching", () => { expect( checkAuthorization( @@ -339,7 +320,6 @@ describe("checkAuthorization", () => { accessLevel: AccessLevel.Admin, dbRole: DbRole.Committee, committeeIdentifier: CommitteeIdentifier.techCommittee, - committeeRole: CommitteeRole.Chair, }, techChair ) diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index d3ddcb0b..070760bd 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -1,41 +1,17 @@ import type { PersonNode } from "../api/resources/Person.js"; -import { roleToAccessLevel } from "../authorization/role.js"; -import type { - AccessLevel, - AuthSource, - Authorization, - CommitteeIdentifier, - CommitteeRole, - DbRole, -} from "../authorization/structures.js"; +import type { AuthSource } from "../authorization/structures.js"; export interface UserData { - auth: Authorization; userId?: string; - teamIds?: string[]; - captainOfTeamIds?: string[]; authSource: AuthSource; } export function makeUserData( person: PersonNode, - authSource: AuthSource, - teamIds?: string[], - captainOfTeamIds?: string[], - committees: { identifier: CommitteeIdentifier; role: CommitteeRole }[] = [] + authSource: AuthSource ): UserData { return { - auth: { - dbRole: person.dbRole, - committees, - accessLevel: roleToAccessLevel({ - dbRole: person.dbRole, - committees, - }), - }, userId: person.id, - teamIds, - captainOfTeamIds, authSource, }; } @@ -44,10 +20,4 @@ export interface JwtPayload { sub?: string; // The type of authentication used to log in (e.g. "uky-linkblue" or "anonymous") auth_source: AuthSource; - // TODO: Replace these fields with either "roles" or "groups" (these are specified in the RFC 7643 Section 4.1.2) - dbRole: DbRole; - committees?: { role: CommitteeRole; identifier: CommitteeIdentifier }[]; - access_level: AccessLevel; - team_ids?: string[]; - captain_of_team_ids?: string[]; } diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 15a25729..45f20e27 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -32,10 +32,10 @@ export interface AuthorizationRule { * Committee > TeamCaptain > TeamMember > Public > None */ minDbRole?: DbRole; - /** - * Exact committee role, cannot be used with minCommitteeRole - */ - committeeRole?: CommitteeRole; + // /** + // * Exact committee role, cannot be used with minCommitteeRole + // */ + // committeeRole?: CommitteeRole; /** * Minimum committee role, cannot be used with committeeRole */ @@ -66,7 +66,7 @@ export function checkAuthorization( accessLevel, committeeIdentifier, committeeIdentifiers, - committeeRole, + // committeeRole, custom, dbRole, minCommitteeRole, @@ -77,11 +77,11 @@ export function checkAuthorization( if (minDbRole != null && dbRole != null) { throw new TypeError(`Cannot specify both dbRole and minDbRole.`); } - if (minCommitteeRole != null && committeeRole != null) { - throw new TypeError( - `Cannot specify both committeeRole and minCommitteeRole.` - ); - } + // if (minCommitteeRole != null && committeeRole != null) { + // throw new TypeError( + // `Cannot specify both committeeRole and minCommitteeRole.` + // ); + // } if (committeeIdentifier != null && committeeIdentifiers != null) { throw new TypeError( `Cannot specify both committeeIdentifier and committeeIdentifiers.` @@ -93,32 +93,43 @@ export function checkAuthorization( // Access Level if (accessLevel != null) { matches &&= authorization.accessLevel >= accessLevel; + console.log( + `Access level ${authorization.accessLevel} >= ${accessLevel}: ${matches}` + ); } // DB role if (dbRole != null) { matches &&= authorization.dbRole === dbRole; + console.log(`DB role ${authorization.dbRole} === ${dbRole}: ${matches}`); } if (minDbRole != null) { matches &&= compareDbRole(authorization.dbRole, minDbRole) >= 0; + console.log(`DB role ${authorization.dbRole} >= ${minDbRole}: ${matches}`); } // Committee role - if (committeeRole != null) { - matches &&= authorization.committees.some( - (committee) => - committee.role === committeeRole && - committee.identifier === committeeIdentifier - ); - } + // if (committeeRole != null) { + // matches &&= authorization.committees.some( + // (committee) => + // committee.role === committeeRole && + // committee.identifier === committeeIdentifier + // ); + // } if (minCommitteeRole != null) { if (authorization.committees.length === 0) { matches = false; + console.log(`No committee roles: ${matches}`); } else { matches &&= authorization.committees.some( (committee) => compareCommitteeRole(committee.role, minCommitteeRole) >= 0 ); + console.log( + `Committee role ${authorization.committees + .map((c) => c.role) + .join(", ")} >= ${minCommitteeRole}: ${matches}` + ); } } @@ -127,16 +138,27 @@ export function checkAuthorization( matches &&= authorization.committees.some( (committee) => committee.identifier === committeeIdentifier ); + console.log( + `Committee identifier ${authorization.committees + .map((c) => c.identifier) + .join(", ")} === ${committeeIdentifier}: ${matches}` + ); } if (committeeIdentifiers != null) { matches &&= authorization.committees.some((committee) => committeeIdentifiers.includes(committee.identifier) ); + console.log( + `Committee identifier ${authorization.committees + .map((c) => c.identifier) + .join(", ")} in ${committeeIdentifiers.join(", ")}: ${matches}` + ); } // Custom auth checker if (custom != null) { matches &&= custom(authorization); + console.log(`Custom auth check: ${matches}`); } return matches; } @@ -173,6 +195,7 @@ export interface AuthorizationContext { authenticatedUser: PersonNode | null; effectiveCommitteeRoles: EffectiveCommitteeRole[]; userData: UserData; + authorization: Authorization; } export function AccessControl< @@ -186,13 +209,13 @@ export function AccessControl< ) => { const { context, args } = resolverData; const root = resolverData.root as RootType; - const { userData, authenticatedUser } = context; + const { userData, authenticatedUser, authorization } = context; let ok = false; for (const rule of params) { if (rule.accessLevel != null) { - if (rule.accessLevel > userData.auth.accessLevel) { + if (rule.accessLevel > authorization.accessLevel) { continue; } } @@ -205,7 +228,7 @@ export function AccessControl< ); } const matches = rule.authRules.some((rule) => - checkAuthorization(rule, userData.auth) + checkAuthorization(rule, authorization) ); if (!matches) { continue; diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index a2628f92..05cbf34a 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -49,7 +49,7 @@ const documents = { "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n": types.PersonViewerFragmentFragmentDoc, "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, - "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n": types.LoginStateDocument, + "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n": types.LoginStateDocument, "\n mutation CommitConfigChanges($changes: [CreateConfigurationInput!]!) {\n createConfigurations(input: $changes) {\n ok\n }\n }\n": types.CommitConfigChangesDocument, "\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n": types.ConfigFragmentFragmentDoc, "\n query ConfigQuery {\n allConfigurations {\n data {\n ...ConfigFragment\n }\n }\n }\n ": types.ConfigQueryDocument, @@ -248,7 +248,7 @@ export function graphql(source: "\n fragment TeamViewerFragment on TeamNode {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n dbRole\n }\n }\n"]; +export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 2416e8d3..4a748555 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -2174,7 +2174,7 @@ export type TeamViewerFragmentFragment = { readonly __typename?: 'TeamNode', rea export type LoginStateQueryVariables = Exact<{ [key: string]: never; }>; -export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly dbRole: DbRole } }; +export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly dbRole: DbRole, readonly effectiveCommitteeRoles: ReadonlyArray<{ readonly __typename?: 'EffectiveCommitteeRole', readonly role: CommitteeRole, readonly committee: CommitteeIdentifier }> } }; export type CommitConfigChangesMutationVariables = Exact<{ changes: ReadonlyArray | CreateConfigurationInput; @@ -2494,7 +2494,7 @@ export const NotificationsTableQueryDocument = {"kind":"Document","definitions": export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]}}]} as unknown as DocumentNode; +export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"effectiveCommitteeRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"committee"}}]}}]}}]}}]} as unknown as DocumentNode; export const CommitConfigChangesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitConfigChanges"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"changes"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateConfigurationInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createConfigurations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"changes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const ConfigQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ConfigQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allConfigurations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ConfigFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const CreateEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/server/src/lib/auth/index.ts b/packages/server/src/lib/auth/index.ts index f0ec07d5..ce6ef284 100644 --- a/packages/server/src/lib/auth/index.ts +++ b/packages/server/src/lib/auth/index.ts @@ -1,10 +1,5 @@ import type { JwtPayload, UserData } from "@ukdanceblue/common"; -import { - AccessLevel, - AuthSource, - CommitteeRole, - DbRole, -} from "@ukdanceblue/common"; +import { AuthSource } from "@ukdanceblue/common"; import type { Request } from "express"; import jsonwebtoken from "jsonwebtoken"; @@ -20,15 +15,7 @@ export function isValidJwtPayload(payload: unknown): payload is JwtPayload { if (typeof payload !== "object" || payload === null) { return false; } - const { - sub, - auth_source, - dbRole, - committees, - access_level, - team_ids, - captain_of_team_ids, - } = payload as Record; + const { sub, auth_source } = payload as Record; if (sub !== undefined && typeof sub !== "string") { return false; } @@ -39,55 +26,6 @@ export function isValidJwtPayload(payload: unknown): payload is JwtPayload { ) { return false; } - if ( - typeof dbRole !== "string" || - !Object.values(DbRole).includes(dbRole as DbRole) - ) { - return false; - } - // if ( - // committee_role !== undefined && - // (typeof committee_role !== "string" || - // !Object.values(CommitteeRole).includes(committee_role as CommitteeRole)) - // ) { - // return false; - // } - // if (committee !== undefined && typeof committee !== "string") { - // return false; - // } - if (committees) { - if (!Array.isArray(committees)) { - return false; - } - for (const committee of committees as unknown[]) { - if ( - typeof committee !== "object" || - committee === null || - typeof (committee as { role?: unknown }).role !== "string" || - !Object.values(CommitteeRole).includes( - (committee as { role?: unknown }).role as CommitteeRole - ) || - typeof (committee as { identifier?: unknown }).identifier !== "string" - ) { - return false; - } - } - } - if ( - typeof access_level !== "number" || - !Object.values(AccessLevel).includes(access_level as AccessLevel) - ) { - return false; - } - if (team_ids !== undefined && !Array.isArray(team_ids)) { - return false; - } - if ( - captain_of_team_ids !== undefined && - !Array.isArray(captain_of_team_ids) - ) { - return false; - } return true; } @@ -105,22 +43,11 @@ export function makeUserJwt(user: UserData): string { (user.authSource as string) === "UkyLinkblue" ? AuthSource.LinkBlue : user.authSource, - dbRole: user.auth.dbRole, - access_level: user.auth.accessLevel, }; if (user.userId) { payload.sub = user.userId; } - if (user.auth.committees.length > 0) { - payload.committees = user.auth.committees; - } - if (user.teamIds) { - payload.team_ids = user.teamIds; - } - if (user.captainOfTeamIds) { - payload.captain_of_team_ids = user.captainOfTeamIds; - } return jsonwebtoken.sign(payload, jwtSecret, { issuer: jwtIssuer, @@ -147,33 +74,13 @@ export function parseUserJwt(token: string): UserData { throw new Error("Invalid JWT payload"); } - if ( - payload.auth_source === AuthSource.Anonymous && - payload.access_level > AccessLevel.Public - ) { - throw new jsonwebtoken.JsonWebTokenError( - "Anonymous users cannot have access levels greater than public" - ); - } - const userData: UserData = { - auth: { - accessLevel: payload.access_level, - dbRole: payload.dbRole, - committees: payload.committees || [], - }, authSource: payload.auth_source, }; if (payload.sub) { userData.userId = payload.sub; } - if (payload.team_ids) { - userData.teamIds = payload.team_ids; - } - if (payload.captain_of_team_ids) { - userData.captainOfTeamIds = payload.captain_of_team_ids; - } return userData; } diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index 99143b3c..e431bbaf 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -35,7 +35,7 @@ export class LoginStateResolver { return { loggedIn: ctx.authenticatedUser != null, effectiveCommitteeRoles: ctx.effectiveCommitteeRoles, - dbRole: ctx.userData.auth.dbRole, + dbRole: ctx.authorization.dbRole, authSource: ctx.userData.authSource, }; } diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index c555fcd0..2a32d7c4 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -1,7 +1,12 @@ import type { ContextFunction } from "@apollo/server"; import type { KoaContextFunctionArgument } from "@as-integrations/koa"; import type { AuthorizationContext } from "@ukdanceblue/common"; -import { AuthSource, MembershipPositionType } from "@ukdanceblue/common"; +import { + AuthSource, + CommitteeRole, + DbRole, + roleToAccessLevel, +} from "@ukdanceblue/common"; import type { DefaultState } from "koa"; import { Container } from "typedi"; @@ -30,22 +35,22 @@ export const graphqlContextFunction: ContextFunction< authenticatedUser: null, effectiveCommitteeRoles: [], userData: { - auth: defaultAuthorization, authSource: AuthSource.None, }, + authorization: defaultAuthorization, contextErrors: [], }; } - const { userId, auth, authSource } = parseUserJwt(token); + const { userId, authSource } = parseUserJwt(token); if (!userId) { logger.trace("graphqlContextFunction No userId found"); return { authenticatedUser: null, effectiveCommitteeRoles: [], userData: { - auth, authSource, }, + authorization: defaultAuthorization, contextErrors: [], }; } @@ -60,25 +65,61 @@ export const graphqlContextFunction: ContextFunction< person, personRepository ); + logger.trace("graphqlContextFunction Found user", personResource); + + const memberships = await personRepository.findCommitteeMembershipsOfPerson( + { id: person.id } + ); + const committees = + memberships + ?.map((membership) => + membership.team.correspondingCommittee + ? { + identifier: membership.team.correspondingCommittee.identifier, + role: membership.committeeRole ?? CommitteeRole.Member, + } + : undefined + ) + .filter( + (committee): committee is NonNullable => + committee != null + ) ?? []; + logger.trace("graphqlContextFunction Found committees", committees); const effectiveCommitteeRoles = await personRepository.getEffectiveCommitteeRolesOfPerson({ id: person.id, }); + logger.trace( + "graphqlContextFunction Effective committee roles", + effectiveCommitteeRoles + ); - logger.trace("graphqlContextFunction Found user", personResource); + let dbRole: DbRole; + if (effectiveCommitteeRoles.length > 0) { + dbRole = DbRole.Committee; + } else if ( + authSource === AuthSource.LinkBlue || + authSource === AuthSource.Demo + ) { + dbRole = DbRole.UKY; + } else if (authSource === AuthSource.Anonymous) { + dbRole = DbRole.Public; + } else { + dbRole = DbRole.None; + } return { authenticatedUser: personResource, effectiveCommitteeRoles, userData: { - auth, userId, - teamIds: person.memberships.map((m) => m.team.uuid), - captainOfTeamIds: person.memberships - .filter((m) => m.position === MembershipPositionType.Captain) - .map((m) => m.team.uuid), authSource, }, + authorization: { + committees, + dbRole, + accessLevel: roleToAccessLevel({ dbRole, committees }), + }, contextErrors: [], }; } else { @@ -87,9 +128,9 @@ export const graphqlContextFunction: ContextFunction< authenticatedUser: null, effectiveCommitteeRoles: [], userData: { - auth: defaultAuthorization, authSource: AuthSource.None, }, + authorization: defaultAuthorization, contextErrors: ["User not found"], }; } From 24d424296ccce914078c0cf89ff4df4f456e0139 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 20:32:30 +0000 Subject: [PATCH 055/153] Finish simplifying JWT and auth stuff --- .../common/lib/authorization/accessControl.ts | 33 ++++++++++++------- packages/portal/src/hooks/useLoginState.ts | 18 +++++++--- .../repositories/person/PersonRepository.ts | 6 +++- .../server/src/resolvers/PersonResolver.ts | 8 ++--- packages/server/src/resolvers/TeamResolver.ts | 6 ++-- packages/server/src/resolvers/context.ts | 17 ++++++++++ .../server/src/routes/api/auth/anonymous.ts | 7 +--- packages/server/src/routes/api/auth/demo.ts | 16 +-------- .../src/routes/api/auth/oidcCallback.ts | 12 ++----- 9 files changed, 70 insertions(+), 53 deletions(-) diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 45f20e27..971acc2f 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -8,7 +8,9 @@ import type { CommitteeRole, DbRole, EffectiveCommitteeRole, + MembershipPositionType, PersonNode, + TeamType, UserData, } from "../index.js"; import { @@ -163,6 +165,14 @@ export function checkAuthorization( return matches; } +interface ExtractorData { + authenticatedUser: PersonNode | null; + effectiveCommitteeRoles: EffectiveCommitteeRole[]; + teamMemberships: SimpleTeamMembership[]; + userData: UserData; + authorization: Authorization; +} + /** * An AccessControlParam accepts a user if: * @@ -177,23 +187,24 @@ export interface AccessControlParam< accessLevel?: AccessLevel; argumentMatch?: { argument: string | ((args: ArgsDictionary) => Primitive | Primitive[]); - extractor: ( - userData: UserData, - person: PersonNode | null - ) => Primitive | Primitive[]; + extractor: (param: ExtractorData) => Primitive | Primitive[]; }[]; rootMatch?: { root: string | ((root: RootType) => Primitive | Primitive[]); - extractor: ( - userData: UserData, - person: PersonNode | null - ) => Primitive | Primitive[]; + extractor: (param: ExtractorData) => Primitive | Primitive[]; }[]; } +export interface SimpleTeamMembership { + teamType: TeamType; + teamId: string; + position: MembershipPositionType; +} + export interface AuthorizationContext { authenticatedUser: PersonNode | null; effectiveCommitteeRoles: EffectiveCommitteeRole[]; + teamMemberships: SimpleTeamMembership[]; userData: UserData; authorization: Authorization; } @@ -209,7 +220,7 @@ export function AccessControl< ) => { const { context, args } = resolverData; const root = resolverData.root as RootType; - const { userData, authenticatedUser, authorization } = context; + const { authorization } = context; let ok = false; @@ -247,7 +258,7 @@ export function AccessControl< "FieldMatchAuthorized argument is null or undefined." ); } - const expectedValue = match.extractor(userData, authenticatedUser); + const expectedValue = match.extractor(context); if (Array.isArray(expectedValue)) { if (Array.isArray(argValue)) { @@ -279,7 +290,7 @@ export function AccessControl< "FieldMatchAuthorized root is null or undefined." ); } - const expectedValue = match.extractor(userData, authenticatedUser); + const expectedValue = match.extractor(context); if (Array.isArray(expectedValue)) { if (Array.isArray(rootValue)) { diff --git a/packages/portal/src/hooks/useLoginState.ts b/packages/portal/src/hooks/useLoginState.ts index d2dd2442..4734d3c2 100644 --- a/packages/portal/src/hooks/useLoginState.ts +++ b/packages/portal/src/hooks/useLoginState.ts @@ -1,5 +1,5 @@ import type { Authorization } from "@ukdanceblue/common"; -import { AccessLevel, defaultAuthorization } from "@ukdanceblue/common"; +import { defaultAuthorization, roleToAccessLevel } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; @@ -8,6 +8,10 @@ const loginStateDocument = graphql(/* GraphQL */ ` loginState { loggedIn dbRole + effectiveCommitteeRoles { + role + committee + } } } `); @@ -35,13 +39,19 @@ export function useLoginState(): { }; } + const committees = data.loginState.effectiveCommitteeRoles.map( + ({ committee, role }) => ({ identifier: committee, role }) + ); + return { loggedIn: data.loginState.loggedIn, authorization: { + committees, dbRole: data.loginState.dbRole, - // TODO: Add committee info back here - accessLevel: AccessLevel.Public, - committees: [], + accessLevel: roleToAccessLevel({ + dbRole: data.loginState.dbRole, + committees, + }), }, }; } diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 1d35261b..6715de3d 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -292,12 +292,16 @@ export class PersonRepository { committeeRole: CommitteeRole; } | Record = {}, - types: TeamType[] | undefined = undefined + types: TeamType[] | undefined = undefined, + includeTeam: boolean = false ) { const rows = await this.prisma.person.findUnique({ where: param, select: { memberships: { + include: { + team: includeTeam, + }, where: { AND: [ opts, diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 8b568bc9..34e3bba6 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -340,7 +340,7 @@ export class PersonResolver { rootMatch: [ { root: "uuid", - extractor: (userData) => userData.userId, + extractor: ({ userData }) => userData.userId, }, ], } @@ -373,7 +373,7 @@ export class PersonResolver { rootMatch: [ { root: "uuid", - extractor: (userData) => userData.userId, + extractor: ({ userData }) => userData.userId, }, ], } @@ -401,7 +401,7 @@ export class PersonResolver { rootMatch: [ { root: "uuid", - extractor: (userData) => userData.userId, + extractor: ({ userData }) => userData.userId, }, ], } @@ -429,7 +429,7 @@ export class PersonResolver { rootMatch: [ { root: "uuid", - extractor: (userData) => userData.userId, + extractor: ({ userData }) => userData.userId, }, ], } diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index b4abcf93..4525a996 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -298,7 +298,8 @@ export class TeamResolver { rootMatch: [ { root: "uuid", - extractor: ({ teamIds }) => teamIds, + extractor: ({ teamMemberships }) => + teamMemberships.map(({ teamId }) => teamId), }, ], } @@ -331,7 +332,8 @@ export class TeamResolver { rootMatch: [ { root: "uuid", - extractor: ({ teamIds }) => teamIds, + extractor: ({ teamMemberships }) => + teamMemberships.map(({ teamId }) => teamId), }, ], } diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 2a32d7c4..70a68697 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -34,6 +34,7 @@ export const graphqlContextFunction: ContextFunction< return { authenticatedUser: null, effectiveCommitteeRoles: [], + teamMemberships: [], userData: { authSource: AuthSource.None, }, @@ -47,6 +48,7 @@ export const graphqlContextFunction: ContextFunction< return { authenticatedUser: null, effectiveCommitteeRoles: [], + teamMemberships: [], userData: { authSource, }, @@ -86,6 +88,14 @@ export const graphqlContextFunction: ContextFunction< ) ?? []; logger.trace("graphqlContextFunction Found committees", committees); + const teamMemberships = await personRepository.findMembershipsOfPerson({ + id: person.id, + }); + logger.trace( + "graphqlContextFunction Found team memberships", + teamMemberships + ); + const effectiveCommitteeRoles = await personRepository.getEffectiveCommitteeRolesOfPerson({ id: person.id, @@ -111,6 +121,12 @@ export const graphqlContextFunction: ContextFunction< return { authenticatedUser: personResource, effectiveCommitteeRoles, + teamMemberships: + teamMemberships?.map((membership) => ({ + teamType: membership.team.type, + position: membership.position, + teamId: membership.team.uuid, + })) ?? [], userData: { userId, authSource, @@ -127,6 +143,7 @@ export const graphqlContextFunction: ContextFunction< return { authenticatedUser: null, effectiveCommitteeRoles: [], + teamMemberships: [], userData: { authSource: AuthSource.None, }, diff --git a/packages/server/src/routes/api/auth/anonymous.ts b/packages/server/src/routes/api/auth/anonymous.ts index b8304af7..f6ec1f34 100644 --- a/packages/server/src/routes/api/auth/anonymous.ts +++ b/packages/server/src/routes/api/auth/anonymous.ts @@ -1,4 +1,4 @@ -import { AccessLevel, AuthSource, DbRole } from "@ukdanceblue/common"; +import { AuthSource } from "@ukdanceblue/common"; import type { Context } from "koa"; import { DateTime } from "luxon"; @@ -27,11 +27,6 @@ export const anonymousLogin = (ctx: Context) => { } const jwt = makeUserJwt({ - auth: { - accessLevel: AccessLevel.Public, - dbRole: DbRole.Public, - committees: [], - }, authSource: AuthSource.Anonymous, }); if (setCookie) { diff --git a/packages/server/src/routes/api/auth/demo.ts b/packages/server/src/routes/api/auth/demo.ts index 708ec98e..82d99e94 100644 --- a/packages/server/src/routes/api/auth/demo.ts +++ b/packages/server/src/routes/api/auth/demo.ts @@ -1,9 +1,4 @@ -import { - AccessLevel, - AuthSource, - DbRole, - MembershipPositionType, -} from "@ukdanceblue/common"; +import { AuthSource } from "@ukdanceblue/common"; import type { Context } from "koa"; import { DateTime } from "luxon"; @@ -35,16 +30,7 @@ export const demoLogin = async (ctx: Context) => { const person = await getOrMakeDemoUser(); const jwt = makeUserJwt({ - auth: { - accessLevel: AccessLevel.UKY, - dbRole: DbRole.UKY, - committees: [], - }, userId: person.uuid, - teamIds: person.memberships.map((m) => m.team.uuid), - captainOfTeamIds: person.memberships - .filter((m) => m.position === MembershipPositionType.Captain) - .map((m) => m.team.uuid), authSource: AuthSource.Demo, }); if (setCookie) { diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index a00e6d60..549b289b 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -1,10 +1,6 @@ import type { IncomingMessage } from "node:http"; -import { - AuthSource, - MembershipPositionType, - makeUserData, -} from "@ukdanceblue/common"; +import { AuthSource, makeUserData } from "@ukdanceblue/common"; import createHttpError from "http-errors"; import jsonwebtoken from "jsonwebtoken"; import type { Context } from "koa"; @@ -135,11 +131,7 @@ export const oidcCallback = async (ctx: Context) => { const jwt = makeUserJwt( makeUserData( await personModelToResource(updatedPerson, personRepository), - AuthSource.LinkBlue, - currentPerson.memberships.map((m) => m.team.uuid), - currentPerson.memberships - .filter((m) => m.position === MembershipPositionType.Captain) - .map((m) => m.team.uuid) + AuthSource.LinkBlue ) ); let redirectTo = session.redirectToAfterLogin; From a6375b1869ce3da42894274108c71c66314122dc Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 21:44:13 +0000 Subject: [PATCH 056/153] Refactor GraphQL types and resolvers for LoginState --- .../lib/graphql-client-admin/graphql.ts | 1 - .../lib/graphql-client-public/graphql.ts | 1 - packages/server/src/resolvers/LoginState.ts | 4 --- .../server/src/resolvers/PersonResolver.ts | 3 +- packages/server/src/resolvers/context.ts | 32 ++++++++++++------- schema.graphql | 1 - 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 4a748555..1768223b 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -754,7 +754,6 @@ export type LoginState = { readonly dbRole: DbRole; readonly effectiveCommitteeRoles: ReadonlyArray; readonly loggedIn: Scalars['Boolean']['output']; - readonly person?: Maybe; }; export type MarathonHourNode = Node & { diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 293f414c..123b9ea4 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -754,7 +754,6 @@ export type LoginState = { readonly dbRole: DbRole; readonly effectiveCommitteeRoles: ReadonlyArray; readonly loggedIn: Scalars['Boolean']['output']; - readonly person?: Maybe; }; export type MarathonHourNode = Node & { diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index e431bbaf..d6cc709a 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -2,7 +2,6 @@ import { AuthSource, DbRole, EffectiveCommitteeRole, - PersonNode, } from "@ukdanceblue/common"; import { Ctx, Field, ObjectType, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; @@ -22,9 +21,6 @@ export class LoginState { @Field(() => [EffectiveCommitteeRole]) effectiveCommitteeRoles!: EffectiveCommitteeRole[]; - - @Field(() => PersonNode, { nullable: true }) - person?: PersonNode; } @Resolver(() => LoginState) diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 34e3bba6..6652468c 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -152,6 +152,7 @@ export class PersonResolver { private readonly membershipRepository: MembershipRepository ) {} + @AccessControl({ accessLevel: AccessLevel.Committee }) @Query(() => GetPersonResponse, { name: "person" }) async getByUuid(@Arg("uuid") uuid: string): Promise { const row = await this.personRepository.findPersonByUnique({ uuid }); @@ -220,7 +221,7 @@ export class PersonResolver { } @Query(() => GetPersonResponse, { name: "me" }) - me(@Ctx() ctx: GraphQLContext): GetPersonResponse | null { + me(@Ctx() ctx: GraphQLContext): GetPersonResponse { return GetPersonResponse.newOk( ctx.authenticatedUser ); diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 70a68697..02455a92 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -86,14 +86,20 @@ export const graphqlContextFunction: ContextFunction< (committee): committee is NonNullable => committee != null ) ?? []; - logger.trace("graphqlContextFunction Found committees", committees); + logger.trace("graphqlContextFunction Found committees", ...committees); - const teamMemberships = await personRepository.findMembershipsOfPerson({ - id: person.id, - }); + const teamMemberships = + (await personRepository.findMembershipsOfPerson( + { + id: person.id, + }, + {}, + undefined, + true + )) ?? []; logger.trace( "graphqlContextFunction Found team memberships", - teamMemberships + ...teamMemberships ); const effectiveCommitteeRoles = @@ -102,7 +108,7 @@ export const graphqlContextFunction: ContextFunction< }); logger.trace( "graphqlContextFunction Effective committee roles", - effectiveCommitteeRoles + ...effectiveCommitteeRoles ); let dbRole: DbRole; @@ -118,15 +124,17 @@ export const graphqlContextFunction: ContextFunction< } else { dbRole = DbRole.None; } + + logger.trace("graphqlContextFunction", { dbRole }); + return { authenticatedUser: personResource, effectiveCommitteeRoles, - teamMemberships: - teamMemberships?.map((membership) => ({ - teamType: membership.team.type, - position: membership.position, - teamId: membership.team.uuid, - })) ?? [], + teamMemberships: teamMemberships.map((membership) => ({ + teamType: membership.team.type, + position: membership.position, + teamId: membership.team.uuid, + })), userData: { userId, authSource, diff --git a/schema.graphql b/schema.graphql index 6d798c84..338e0508 100644 --- a/schema.graphql +++ b/schema.graphql @@ -763,7 +763,6 @@ type LoginState { dbRole: DbRole! effectiveCommitteeRoles: [EffectiveCommitteeRole!]! loggedIn: Boolean! - person: PersonNode } type MarathonHourNode implements Node { From fb6ebaf22c516f74c503a94fa2b28641fd93a0dc Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 21:58:16 +0000 Subject: [PATCH 057/153] Remove unused common code --- .../lib/api/filtering/ListQueryTypes.ts | 4 +- packages/common/lib/index.ts | 4 - packages/common/lib/react.ts | 2 - packages/common/lib/ui/formReducer.ts | 78 ------------------- packages/common/lib/ui/reactLib.ts | 22 ------ packages/common/package.json | 5 -- 6 files changed, 2 insertions(+), 113 deletions(-) delete mode 100644 packages/common/lib/react.ts delete mode 100644 packages/common/lib/ui/formReducer.ts delete mode 100644 packages/common/lib/ui/reactLib.ts diff --git a/packages/common/lib/api/filtering/ListQueryTypes.ts b/packages/common/lib/api/filtering/ListQueryTypes.ts index 3cbfd8f5..4933a56c 100644 --- a/packages/common/lib/api/filtering/ListQueryTypes.ts +++ b/packages/common/lib/api/filtering/ListQueryTypes.ts @@ -68,8 +68,8 @@ export interface PaginationOptions { } export const SortDirection = { - ASCENDING: "ASCENDING", - DESCENDING: "DESCENDING", + ASCENDING: "ASC", + DESCENDING: "DESC", } as const; export type SortDirection = (typeof SortDirection)[keyof typeof SortDirection]; diff --git a/packages/common/lib/index.ts b/packages/common/lib/index.ts index dc632569..3c190d2b 100644 --- a/packages/common/lib/index.ts +++ b/packages/common/lib/index.ts @@ -44,10 +44,6 @@ export * from "./api/filtering/list-query-args/registerFilterKeyEnums.js"; export * from "./ui/color.js"; -// React specific code: -export * from "./ui/formReducer.js"; -export { initializeReact } from "./ui/reactLib.js"; - /* Note: If the .js is missing in a bunch of places, use this regex to replace: diff --git a/packages/common/lib/react.ts b/packages/common/lib/react.ts deleted file mode 100644 index 62b0a456..00000000 --- a/packages/common/lib/react.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./ui/formReducer.js"; -export * from "./ui/reactLib.js"; diff --git a/packages/common/lib/ui/formReducer.ts b/packages/common/lib/ui/formReducer.ts deleted file mode 100644 index 7d8ef3c1..00000000 --- a/packages/common/lib/ui/formReducer.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { PrimitiveObject } from "../utility/primitive/TypeUtils.js"; - -import { getReact } from "./reactLib.js"; - -type FormMap = Map; - -export type UpdatePayload = T extends Map ? [k, V] : never; - -export type FormErrors = Partial< - Record ->; - -/** - * Allowed action names: - * - "reset": Resets the form to the initial state - * - "update": Updates the form with a new value - * - "remove-field": Removes a field from the form (ONLY USE FOR OPTIONAL FIELDS) - * - "set": Sets the entire form to a new value - * - * @param initialState The initial state of the form - * @param validator A function that validates the form and returns an object with errors - * @return A tuple with the reducer and the errors - */ -export const useFormReducer = ( - initialState: T, - validator?: (state: T) => FormErrors -) => { - const { useState, useReducer } = getReact(); - - const [errors, setErrors] = useState>({}); - const reducer = useReducer( - ( - state: T, - [keyword, payload]: - | ["reset"] - | ["update", UpdatePayload] - | ["remove-field", keyof T] - | ["set", T] - ): T => { - const updatedState = state; - switch (keyword) { - case "reset": { - return initialState; - } - case "update": { - const [key, newValue] = payload; - updatedState.set(key, newValue); - if (validator) { - setErrors(validator(updatedState)); - } - return updatedState; - } - case "remove-field": { - const updatedState = { - ...state, - }; - updatedState.delete(payload); - if (validator) { - setErrors(validator(updatedState)); - } - return updatedState; - } - case "set": { - if (validator) { - setErrors(validator(payload)); - } - return payload; - } - default: { - throw new Error("Invalid action"); - } - } - }, - initialState - ); - - return [reducer, errors] as const; -}; diff --git a/packages/common/lib/ui/reactLib.ts b/packages/common/lib/ui/reactLib.ts deleted file mode 100644 index bc375847..00000000 --- a/packages/common/lib/ui/reactLib.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { - useReducer as useReducerType, - useState as useStateType, -} from "react"; - -let reactLib: { - useReducer: typeof useReducerType; - useState: typeof useStateType; -} | null = null; - -export const initializeReact = (lib: typeof reactLib) => { - reactLib = lib; -}; - -export const getReact = () => { - if (!reactLib) { - throw new Error( - "You must call initializeReact before using db-app-commons's react functionality!" - ); - } - return reactLib; -}; diff --git a/packages/common/package.json b/packages/common/package.json index 700c6fbf..3b420dec 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -15,11 +15,6 @@ "node": "./dist/index.js", "types": "./dist/index.d.ts" }, - "./react": { - "node": null, - "types": "./dist/react.d.ts", - "default": "./dist/react/index.js" - }, "./client-parsers": { "node": null, "default": "./dist/client-parsers/index.js" From 25ba74add50d078a32d1de25328e1f48b55a6205 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 21:58:47 +0000 Subject: [PATCH 058/153] Remove unused server code --- packages/server/src/lib/InvariantError.ts | 10 - .../server/src/lib/auth/findPersonForLogin.ts | 27 --- .../src/lib/prisma-utils/gqlFilterToSql.ts | 221 ------------------ packages/server/src/lib/sendResponse.ts | 118 ---------- packages/server/src/lib/transformers.ts | 98 -------- packages/server/src/lib/whatwg.ts | 114 --------- .../event/images/EventImagesRepository.ts | 6 +- 7 files changed, 3 insertions(+), 591 deletions(-) delete mode 100644 packages/server/src/lib/InvariantError.ts delete mode 100644 packages/server/src/lib/prisma-utils/gqlFilterToSql.ts delete mode 100644 packages/server/src/lib/sendResponse.ts delete mode 100644 packages/server/src/lib/transformers.ts delete mode 100644 packages/server/src/lib/whatwg.ts diff --git a/packages/server/src/lib/InvariantError.ts b/packages/server/src/lib/InvariantError.ts deleted file mode 100644 index 445a383f..00000000 --- a/packages/server/src/lib/InvariantError.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { logger } from "./logging/logger.js"; - -export class InvariantError extends Error { - readonly name: string = "InvariantError"; - - constructor(message: string) { - super(message); - logger.error("Invariant Violation", message); - } -} diff --git a/packages/server/src/lib/auth/findPersonForLogin.ts b/packages/server/src/lib/auth/findPersonForLogin.ts index 5467da43..d0a503fd 100644 --- a/packages/server/src/lib/auth/findPersonForLogin.ts +++ b/packages/server/src/lib/auth/findPersonForLogin.ts @@ -96,33 +96,6 @@ export async function findPersonForLogin( if (!userInfo.email) { throw new Error("No email provided for new user"); } - // currentPerson = PersonModel.build({ - // authIds, - // email: userData.email, - // }); - - // const { name, linkblue, role } = userData; - - // if (name) { - // currentPerson.name = name; - // } - // if (linkblue) { - // currentPerson.linkblue = linkblue; - // } - // if (role) { - // currentPerson.committeeRole = role.committeeRole; - // currentPerson.committeeName = role.committeeIdentifier; - // } - - // const savedPerson = await currentPerson.save({ - // transaction: t, - // returning: ["id"], - // }); - - // const { uuid: finalPersonUuid } = await savedPerson.save({ - // transaction: t, - // returning: ["uuid"], - // }); const memberOfIds = await Promise.all( memberOf?.map(async (teamId) => { diff --git a/packages/server/src/lib/prisma-utils/gqlFilterToSql.ts b/packages/server/src/lib/prisma-utils/gqlFilterToSql.ts deleted file mode 100644 index efce0112..00000000 --- a/packages/server/src/lib/prisma-utils/gqlFilterToSql.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { Prisma } from "@prisma/client"; -import type { - AbstractBooleanFilterItem, - AbstractDateFilterItem, - AbstractIsNullFilterItem, - AbstractNumericFilterItem, - AbstractOneOfFilterItem, - AbstractStringFilterItem, -} from "@ukdanceblue/common"; -import { - IsComparator, - NumericComparator, - StringComparator, -} from "@ukdanceblue/common"; - -export type FilterItems< - B extends string, - D extends string, - I extends string, - N extends string, - O extends string, - S extends string, -> = - | AbstractBooleanFilterItem - | AbstractDateFilterItem - | AbstractIsNullFilterItem - | AbstractNumericFilterItem - | AbstractOneOfFilterItem - | AbstractStringFilterItem; - -export function stringFilterToSql( - filter: AbstractStringFilterItem -): Prisma.Sql { - switch (filter.comparison) { - case StringComparator.IS: - case StringComparator.EQUALS: { - if (filter.negate) { - // return { not: { equals: filter.value }, mode: "insensitive" }; - return Prisma.sql`NOT ${filter.field} = ${filter.value}`; - } - // return { equals: filter.value }; - return Prisma.sql`${filter.field} = ${filter.value}`; - } - case StringComparator.STARTS_WITH: { - if (filter.negate) { - // return { not: { startsWith: filter.value }, mode: "insensitive" }; - return Prisma.sql`NOT ${filter.field} ILIKE ${filter.value}%`; - } - // return { startsWith: filter.value, mode: "insensitive" }; - return Prisma.sql`${filter.field} ILIKE ${filter.value}%`; - } - case StringComparator.ENDS_WITH: { - if (filter.negate) { - // return { not: { endsWith: filter.value }, mode: "insensitive" }; - return Prisma.sql`NOT ${filter.field} ILIKE %${filter.value}`; - } - // return { endsWith: filter.value, mode: "insensitive" }; - return Prisma.sql`${filter.field} ILIKE %${filter.value}`; - } - case StringComparator.SUBSTRING: { - if (filter.negate) { - // return { not: { contains: filter.value }, mode: "insensitive" }; - return Prisma.sql`NOT ${filter.field} ILIKE %${filter.value}%`; - } - // return { contains: filter.value, mode: "insensitive" }; - return Prisma.sql`${filter.field} ILIKE %${filter.value}%`; - } - default: { - throw new Error( - `Unsupported string comparator: ${String(filter.comparison)}` - ); - } - } -} - -export function booleanFilterToSql( - filter: AbstractBooleanFilterItem -): Prisma.Sql { - switch (filter.comparison) { - case IsComparator.IS: { - if (filter.negate) { - // return { not: { equals: filter.value } }; - return Prisma.sql`NOT ${filter.field} = ${filter.value}`; - } - // return { equals: filter.value }; - return Prisma.sql`${filter.field} = ${filter.value}`; - } - default: { - throw new Error( - `Unsupported boolean comparator: ${String(filter.comparison)}` - ); - } - } -} - -export function dateFilterToSql( - filter: AbstractDateFilterItem -): Prisma.Sql { - switch (filter.comparison) { - case IsComparator.IS: - case NumericComparator.EQUALS: { - if (filter.negate) { - // return { not: { equals: filter.value } }; - return Prisma.sql`NOT ${filter.field} = ${filter.value}`; - } - // return { equals: filter.value }; - return Prisma.sql`${filter.field} = ${filter.value}`; - } - case NumericComparator.GREATER_THAN: { - if (filter.negate) { - // return { not: { gt: filter.value } }; - return Prisma.sql`NOT ${filter.field} > ${filter.value}`; - } - // return { gt: filter.value }; - return Prisma.sql`${filter.field} > ${filter.value}`; - } - case NumericComparator.GREATER_THAN_OR_EQUAL_TO: { - if (filter.negate) { - // return { not: { gte: filter.value } }; - return Prisma.sql`NOT ${filter.field} >= ${filter.value}`; - } - // return { gte: filter.value }; - return Prisma.sql`${filter.field} >= ${filter.value}`; - } - case NumericComparator.LESS_THAN: { - if (filter.negate) { - // return { not: { lt: filter.value } }; - return Prisma.sql`NOT ${filter.field} < ${filter.value}`; - } - // return { lt: filter.value }; - return Prisma.sql`${filter.field} < ${filter.value}`; - } - case NumericComparator.LESS_THAN_OR_EQUAL_TO: { - if (filter.negate) { - // return { not: { lte: filter.value } }; - return Prisma.sql`NOT ${filter.field} <= ${filter.value}`; - } - // return { lte: filter.value }; - return Prisma.sql`${filter.field} <= ${filter.value}`; - } - default: { - throw new Error( - `Unsupported date comparator: ${String(filter.comparison)}` - ); - } - } -} - -export function isNullFilterToSql( - filter: AbstractIsNullFilterItem -): Prisma.Sql { - if (filter.negate) { - // return { not: { equals: null } }; - return Prisma.sql`NOT ${filter.field} IS NULL`; - } - // return { equals: null }; - return Prisma.sql`${filter.field} IS NULL`; -} - -export function numericFilterToSql( - filter: AbstractNumericFilterItem -): Prisma.Sql { - switch (filter.comparison) { - case NumericComparator.EQUALS: { - if (filter.negate) { - // return { not: { equals: filter.value } }; - return Prisma.sql`NOT ${filter.field} = ${filter.value}`; - } - // return { equals: filter.value }; - return Prisma.sql`${filter.field} = ${filter.value}`; - } - case NumericComparator.GREATER_THAN: { - if (filter.negate) { - // return { not: { gt: filter.value } }; - return Prisma.sql`NOT ${filter.field} > ${filter.value}`; - } - // return { gt: filter.value }; - return Prisma.sql`${filter.field} > ${filter.value}`; - } - case NumericComparator.GREATER_THAN_OR_EQUAL_TO: { - if (filter.negate) { - // return { not: { gte: filter.value } }; - return Prisma.sql`NOT ${filter.field} >= ${filter.value}`; - } - // return { gte: filter.value }; - return Prisma.sql`${filter.field} >= ${filter.value}`; - } - case NumericComparator.LESS_THAN: { - if (filter.negate) { - // return { not: { lt: filter.value } }; - return Prisma.sql`NOT ${filter.field} < ${filter.value}`; - } - // return { lt: filter.value }; - return Prisma.sql`${filter.field} < ${filter.value}`; - } - case NumericComparator.LESS_THAN_OR_EQUAL_TO: { - if (filter.negate) { - // return { not: { lte: filter.value } }; - return Prisma.sql`NOT ${filter.field} <= ${filter.value}`; - } - // return { lte: filter.value }; - return Prisma.sql`${filter.field} <= ${filter.value}`; - } - default: { - throw new Error( - `Unsupported numeric comparator: ${String(filter.comparison)}` - ); - } - } -} - -export function oneOfFilterToSql( - filter: AbstractOneOfFilterItem -): Prisma.Sql { - if (filter.negate) { - // return { not: { in: [...filter.value] as never[] } }; - return Prisma.sql`NOT ${filter.field} IN (${filter.value})`; - } - // return { in: [...filter.value] as never[] }; - return Prisma.sql`${filter.field} IN (${filter.value})`; -} diff --git a/packages/server/src/lib/sendResponse.ts b/packages/server/src/lib/sendResponse.ts deleted file mode 100644 index 16563c89..00000000 --- a/packages/server/src/lib/sendResponse.ts +++ /dev/null @@ -1,118 +0,0 @@ -import type { Primitive, PrimitiveObject } from "@ukdanceblue/common"; -import { isPrimitive, isPrimitiveObject } from "@ukdanceblue/common"; -import type { Request, Response } from "express"; - -// Strings will be light blue, numbers will be purple, -// true will be dark green, and false will be light red, -// null will be dark red, and undefined will be dark gray. -const stringColor = "#11aaff"; -const numberColor = "#aa11ff"; -const trueColor = "#11ff11"; -const falseColor = "#cc1111"; -const nullColor = "#ff0000"; -const undefinedColor = "#888888"; - -/** - * Recursively converts a primitive or primitive object to an HTML string - * suitable for including in a document body. - * - * @param content The content to convert - * @param indentationLevel The indentation level to use - * @return The HTML string - */ -function htmlifyJson( - content: Primitive | PrimitiveObject | PrimitiveObject[] | Primitive[], - indentationLevel = 0 -): string { - if (Array.isArray(content)) { - return `
    Array (${ - content.length - } Elements)
      ${content - .map((item) => `
    1. ${htmlifyJson(item, indentationLevel + 1)}
    2. `) - .join("")}
    `; - } - if (isPrimitiveObject(content)) { - // If we are at indent level 0 skip the list - if (indentationLevel === 0) { - return Object.entries(content) - .map( - ([key, value]) => `
    ${key}: ${htmlifyJson(value)}
    ` - ) - .join(""); - } else { - return `
    Object:
      ${Object.entries(content) - .map( - ([key, value]) => - `
    • ${key}: ${htmlifyJson(value, indentationLevel + 1)}
    • ` - ) - .join("")}
    `; - } - } - if (typeof content === "string") { - return `"${content}"`; - } - if (typeof content === "number") { - return `${content}`; - } - if (typeof content === "boolean") { - return `${ - content ? "True" : "False" - }`; - } - if (content === null) { - return `Null`; - } - return `No Content`; -} - -/** - * Sends a response to the client. If the client accepts HTML, it will send - * the content as HTML. Otherwise, it will send the content as JSON. - * If the content is undefined, it will send no body. - * - * @param res The response object - * @param req The request object - * @param content The content to send - * @param status The status code to send - * @return The response - */ -export function sendResponse( - res: Response, - _: Request, - content?: unknown, - status = 200 -) { - res.status(status); - if (content === undefined) { - return res.send(); - } - - return res.format({ - html: () => { - if (!(isPrimitive(content) || isPrimitiveObject(content))) { - const stringifiedContent = JSON.stringify(content, null, 2); - return res.send(stringifiedContent); - } else { - return res - .contentType("text/html") - .send( - `DanceBlue API Viewer${htmlifyJson( - content ?? undefined - )}` - ); - } - }, - json: () => { - return res.json(content); - }, - text: () => { - const stringifiedContent = JSON.stringify(content, null, 2); - return res - .contentType("text/plain; charset=utf-8") - .send(stringifiedContent); - }, - default: () => { - return res.status(406).send("Not Acceptable"); - }, - }); -} diff --git a/packages/server/src/lib/transformers.ts b/packages/server/src/lib/transformers.ts deleted file mode 100644 index 05f9be19..00000000 --- a/packages/server/src/lib/transformers.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { LuxonError } from "@ukdanceblue/common"; -import { DateTime, Interval } from "luxon"; -import { - Range, - parse as parseRange, - serialize as serializeRange, -} from "postgres-range"; - -export const luxonDateTimeJsDateTransformer = { - from: (value: Date): DateTime => { - return DateTime.fromJSDate(value, { zone: "utc" }); - }, - to: ( - value?: DateTime | null | undefined | Record - ): Date | undefined => { - if (!value) { - return undefined; - } - if (!DateTime.isDateTime(value)) { - throw new Error("Not a DateTime"); - } - return value.toJSDate(); - }, -}; - -export const luxonDateTimeJsDateArrayTransformer = { - from: (value: Date[]): DateTime[] => { - return value.map((date) => DateTime.fromJSDate(date, { zone: "utc" })); - }, - to: (value?: DateTime[] | null | undefined | Record) => { - if (!value) { - return undefined; - } - if (!Array.isArray(value)) { - throw new TypeError("Not an array"); - } - return value.map((dateTime) => { - if (!DateTime.isDateTime(dateTime)) { - throw new Error("Not a DateTime"); - } - return dateTime.toJSDate(); - }); - }, -}; - -export const luxonIntervalPgRangeTransformer = { - from: (value: string) => { - const range = parseRange(value, (value) => DateTime.fromISO(value)); - if (range.lower == null || range.upper == null) { - throw new Error("Not a range"); - } - return Interval.fromDateTimes(range.lower, range.upper); - }, - to: (value?: Interval | null | undefined | Record) => { - if (value == null) { - return null; - } - if ( - !Interval.isInterval(value) || - value.start == null || - value.end == null - ) { - throw new Error("Not an Interval"); - } - if (!value.isValid) { - throw new LuxonError(value); - } - const range = new Range(value.start, value.end, 0); - return serializeRange(range, (dateTime) => { - const iso = dateTime.toISO(); - if (iso == null) { - const error = dateTime.isValid - ? new Error("Not an ISO string") - : new LuxonError(dateTime); - throw error; - } - return iso; - }); - }, -}; - -export const luxonDateISOStringTransformer = { - from: (value: string) => { - return DateTime.fromISO(value, { zone: "utc" }); - }, - to: (value?: DateTime | null | undefined | Record) => { - return value?.toISODate?.(); - }, -}; - -export const luxonTimeISOStringTransformer = { - from: (value: string) => { - return DateTime.fromISO(value, { zone: "utc" }); - }, - to: (value?: DateTime | null | undefined | Record) => { - return value?.toISOTime?.(); - }, -}; diff --git a/packages/server/src/lib/whatwg.ts b/packages/server/src/lib/whatwg.ts deleted file mode 100644 index c741defc..00000000 --- a/packages/server/src/lib/whatwg.ts +++ /dev/null @@ -1,114 +0,0 @@ -const sparseHttpTokenCodePoints = new Set([ - 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x2a, 0x2b, 0x2d, 0x2e, 0x5e, 0x5f, 0x60, - 0x7c, 0x7e, -]); -export function isHttpTokenCodePoint(codePoint: number | undefined): boolean { - if (codePoint === undefined) return false; - // First check if alphanumeric - if (codePoint >= 0x30 && codePoint <= 0x39) return true; - if (codePoint >= 0x41 && codePoint <= 0x5a) return true; - if (codePoint >= 0x61 && codePoint <= 0x7a) return true; - // Then check if in the list - return sparseHttpTokenCodePoints.has(codePoint); -} -export function isHttpQuotedStringTokenCodePoint( - codePoint: number | undefined -): boolean { - if (codePoint === undefined) return false; - if (codePoint === 0x09) return true; - if (codePoint >= 0x20 && codePoint <= 0x7e) return true; - if (codePoint >= 0x80 && codePoint <= 0xff) return true; - return false; -} -export function isHttpWhitespace(codePoint: number | undefined): boolean { - if (codePoint === undefined) return false; - return ( - codePoint === 0x0a || // LF - codePoint === 0x0d || // CR - codePoint === 0x09 || // TAB - codePoint === 0x20 // SPACE - ); -} -export function trimHttpWhitespace( - input: string, - direction: "start" | "end" | "both" = "both" -): string { - let start = 0; - let end = input.length; - if (direction === "start" || direction === "both") { - while (start < end && isHttpWhitespace(input.codePointAt(start))) { - start++; - } - } - if (direction === "end" || direction === "both") { - while (end > start && isHttpWhitespace(input.codePointAt(end - 1))) { - end--; - } - } - return input.slice(start, end); -} - -export function collectHttpQuotedString( - input: string, - position: number, - extractValue = false -): { output: string; position: number } { - const positionStart = position; - let value = ""; - - // Assert: the code point at position within input is U+0022 ("). - if (input.codePointAt(position) !== 0x22) { - throw new Error('Invalid input. Expected starting quote (").'); - } - - // Advance position by 1. - position++; - - for (;;) { - // Append the result of collecting a sequence of code points that are not U+0022 (") or U+005C (\) from input, given position, to value. - while ( - position < input.length && - input.codePointAt(position) !== 0x22 && - input.codePointAt(position) !== 0x5c - ) { - value += input.charAt(position); - position++; - } - - // If position is past the end of input, then break. - if (position >= input.length) { - break; - } - - // Let quoteOrBackslash be the code point at position within input. - const quoteOrBackslash = input.codePointAt(position); - - // Advance position by 1. - position++; - - if (quoteOrBackslash === 0x5c) { - // If quoteOrBackslash is U+005C (\), then: - if (position >= input.length) { - // If position is past the end of input, then append U+005C (\) to value and break. - value += "\\"; - break; - } - - // Append the code point at position within input to value. - value += input.charAt(position); - // Advance position by 1. - position++; - } else { - // Otherwise: - // Assert: quoteOrBackslash is U+0022 ("). - // Break. - break; - } - } - - return extractValue - ? // If extract-value is true, then return value. - { output: value, position } - : // Return the code points from positionStart to position, inclusive, within input. - { output: input.slice(positionStart, position + 1), position }; -} diff --git a/packages/server/src/repositories/event/images/EventImagesRepository.ts b/packages/server/src/repositories/event/images/EventImagesRepository.ts index 1b20d3f4..d5462533 100644 --- a/packages/server/src/repositories/event/images/EventImagesRepository.ts +++ b/packages/server/src/repositories/event/images/EventImagesRepository.ts @@ -1,9 +1,8 @@ import type { Prisma } from "@prisma/client"; import { PrismaClient } from "@prisma/client"; +import { DetailedError, ErrorCode } from "@ukdanceblue/common"; import { Service } from "typedi"; -import { InvariantError } from "../../../lib/InvariantError.js"; - type UniqueParam = | { eventId: number; @@ -113,7 +112,8 @@ export class EventImagesRepository { } else if (count === 1) { return true; } else { - throw new InvariantError( + throw new DetailedError( + ErrorCode.InternalFailure, "Expected to remove at most one event-image relationship, but removed more than one." ); } From 6ecddfd82f363b488ddffd270ee9221d9c204523 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 26 May 2024 21:59:14 +0000 Subject: [PATCH 059/153] Update TeamsTable filters to use enum values for type and legacy status --- .../lib/api/filtering/ListQueryTypes.ts | 4 +- .../portal/src/elements/tables/TeamsTable.tsx | 52 +++++++++++-------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/packages/common/lib/api/filtering/ListQueryTypes.ts b/packages/common/lib/api/filtering/ListQueryTypes.ts index 4933a56c..f27ef466 100644 --- a/packages/common/lib/api/filtering/ListQueryTypes.ts +++ b/packages/common/lib/api/filtering/ListQueryTypes.ts @@ -68,8 +68,8 @@ export interface PaginationOptions { } export const SortDirection = { - ASCENDING: "ASC", - DESCENDING: "DESC", + ASCENDING: "asc", + DESCENDING: "desc", } as const; export type SortDirection = (typeof SortDirection)[keyof typeof SortDirection]; diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index 1b1a7623..a2cede9e 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -3,7 +3,7 @@ import { useListQuery } from "@hooks/useListQuery"; import { useMakeStringSearchFilterProps } from "@hooks/useMakeSearchFilterProps"; import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; import { useNavigate } from "@tanstack/react-router"; -import { SortDirection } from "@ukdanceblue/common"; +import { SortDirection, TeamLegacyStatus, TeamType } from "@ukdanceblue/common"; import { getFragmentData, graphql, @@ -112,31 +112,41 @@ export const TeamsTable = () => { title: "Type", dataIndex: "type", sorter: true, - filters: [ - { - text: "Committee", - value: "Committee", - }, - { - text: "Spirit", - value: "Spirit", - }, - ], + filters: Object.entries(TeamType).map(([key, value]) => ({ + text: key, + value, + })), }, { title: "Legacy Status", dataIndex: "legacyStatus", sorter: true, - filters: [ - { - text: "New Team", - value: "NewTeam", - }, - { - text: "Returning Team", - value: "ReturningTeam", - }, - ], + filters: Object.values(TeamLegacyStatus).map((value) => { + let text: string; + switch (value) { + case TeamLegacyStatus.NewTeam: { + text = "New Team"; + break; + } + case TeamLegacyStatus.ReturningTeam: { + text = "Returning Team"; + break; + } + case TeamLegacyStatus.DemoTeam: { + text = "Demo Team"; + break; + } + default: { + value satisfies never; + text = String(value); + break; + } + } + return { + text, + value, + }; + }), render: (value) => { switch (value) { case "NewTeam": { From 503d214c4d224a663d73531f8b262ac0615a4755 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 27 May 2024 01:21:29 +0000 Subject: [PATCH 060/153] Rename SortDirection.*CENDING to *c --- .../lib/api/filtering/ListQueryTypes.ts | 4 +- .../common/lib/graphql-client-admin/gql.ts | 8 +-- .../lib/graphql-client-admin/graphql.ts | 4 +- .../common/lib/graphql-client-public/gql.ts | 8 +-- .../lib/graphql-client-public/graphql.ts | 4 +- .../tab/EventListScreen/eventListUtils.ts | 2 +- .../root/tab/spirit/SpiritStack.tsx | 2 +- .../src/elements/tables/PeopleTable.tsx | 4 +- .../portal/src/elements/tables/TeamsTable.tsx | 8 +-- .../NotificationDeliveriesTable.tsx | 4 +- .../notification/NotificationsTable.tsx | 4 +- .../pages/events/list-events/EventsTable.tsx | 4 +- .../src/pages/images/list/ImagesTable.tsx | 8 ++- .../people/create-person/CreatePersonPage.tsx | 2 +- .../edit-person/EditPersonPage.tsx | 2 +- packages/server/src/lib/graphqlSchema.ts | 50 ++++++++++++------- packages/server/src/prisma.ts | 6 ++- .../committee/CommitteeRepository.ts | 8 ++- .../committee/committeeRepositoryUtils.ts | 2 +- .../configurationRepositoryUtils.ts | 2 +- .../device/deviceRepositoryUtils.ts | 2 +- .../src/repositories/event/EventRepository.ts | 4 +- .../event/eventRepositoryUtils.ts | 2 +- .../image/imageRepositoryUtils.ts | 2 +- .../marathon/marathonRepositoryUtils.ts | 2 +- .../marathonHourRepositoryUtils.ts | 4 +- .../membership/membershipRepositoryUtils.ts | 2 +- .../notificationRepositoryUtils.ts | 2 +- .../notificationDeliveryRepositoryUtils.ts | 2 +- .../person/personRepositoryUtils.ts | 2 +- .../pointEntry/pointEntryRepositoryUtils.ts | 2 +- .../pointOpportunityRepositoryUtils.ts | 2 +- .../repositories/team/teamRepositoryUtils.ts | 2 +- .../src/resolvers/ConfigurationResolver.ts | 2 +- .../server/src/resolvers/DeviceResolver.ts | 4 +- .../server/src/resolvers/EventResolver.ts | 2 +- .../server/src/resolvers/ImageResolver.ts | 2 +- .../server/src/resolvers/MarathonResolver.ts | 4 +- .../src/resolvers/MembershipResolver.ts | 2 +- .../src/resolvers/NotificationResolver.ts | 4 +- .../server/src/resolvers/PersonResolver.ts | 4 +- .../src/resolvers/PointEntryResolver.ts | 4 +- .../src/resolvers/PointOpportunityResolver.ts | 2 +- packages/server/src/resolvers/TeamResolver.ts | 2 +- schema.graphql | 4 +- 45 files changed, 107 insertions(+), 95 deletions(-) diff --git a/packages/common/lib/api/filtering/ListQueryTypes.ts b/packages/common/lib/api/filtering/ListQueryTypes.ts index f27ef466..9c4da7c5 100644 --- a/packages/common/lib/api/filtering/ListQueryTypes.ts +++ b/packages/common/lib/api/filtering/ListQueryTypes.ts @@ -68,8 +68,8 @@ export interface PaginationOptions { } export const SortDirection = { - ASCENDING: "asc", - DESCENDING: "desc", + asc: "asc", + desc: "desc", } as const; export type SortDirection = (typeof SortDirection)[keyof typeof SortDirection]; diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 05cbf34a..8f6143de 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -80,8 +80,8 @@ const documents = { "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n": types.EditMarathonHourDocument, "\n query NotificationManager($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationManagerDocument, "\n query NotificationViewer($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationViewerDocument, - "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.CreatePersonPageDocument, - "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, + "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.CreatePersonPageDocument, + "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, "\n query ViewPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n": types.ViewPersonPageDocument, "\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n": types.EditTeamPageDocument, "\n query ViewTeamPage($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n": types.ViewTeamPageDocument, @@ -372,11 +372,11 @@ export function graphql(source: "\n query NotificationViewer($uuid: String!) {\ /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [ASCENDING]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 1768223b..be9a85a4 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -2517,8 +2517,8 @@ export const EditMarathonHourDataDocument = {"kind":"Document","definitions":[{" export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; -export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"ASCENDING"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index cba15fe4..6ac87cc5 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -30,13 +30,13 @@ const documents = { "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n": types.RootScreenDocumentDocument, "\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n": types.RootScreenAuthFragmentFragmentDoc, - "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, + "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: asc\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, "\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n": types.ServerFeedDocument, "\n fragment HourScreenFragment on MarathonHourNode {\n id\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n": types.HourScreenFragmentFragmentDoc, "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n nextMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n": types.MarathonScreenDocument, "\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n": types.ScoreBoardFragmentFragmentDoc, "\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n": types.HighlightedTeamFragmentFragmentDoc, - "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, + "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, "\n query ActiveMarathonDocument {\n currentMarathon {\n id\n }\n }\n": types.ActiveMarathonDocumentDocument, "\n fragment MyTeamFragment on TeamNode {\n id\n name\n totalPoints\n pointEntries {\n personFrom {\n id\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n": types.MyTeamFragmentFragmentDoc, }; @@ -126,7 +126,7 @@ export function graphql(source: "\n fragment RootScreenAuthFragment on LoginSta /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "): (typeof documents)["\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: ASCENDING\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "]; +export function graphql(source: "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: asc\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "): (typeof documents)["\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: asc\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -150,7 +150,7 @@ export function graphql(source: "\n fragment HighlightedTeamFragment on TeamNod /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [DESCENDING, ASCENDING]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 123b9ea4..2f8aca18 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -2092,8 +2092,8 @@ export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"Oper export const SetDeviceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDevice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterDeviceInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerDevice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"ASCENDING"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; +export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"asc"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; -export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"DESCENDING"},{"kind":"EnumValue","value":"ASCENDING"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"desc"},{"kind":"EnumValue","value":"asc"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ActiveMarathonDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathonDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts b/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts index 9f7dcb2e..e47f86c7 100644 --- a/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts +++ b/packages/mobile/src/navigation/root/tab/EventListScreen/eventListUtils.ts @@ -264,7 +264,7 @@ export const useEvents = ({ value: $lastTimestamp } ] - sortDirection: ASCENDING + sortDirection: asc sortBy: "occurrence" ) { data { diff --git a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx index 5bca889e..7857f9fb 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx @@ -27,7 +27,7 @@ const scoreBoardDocument = graphql(/* GraphQL */ ` teams( sendAll: true sortBy: ["totalPoints", "name"] - sortDirection: [DESCENDING, ASCENDING] + sortDirection: [desc, asc] type: $type ) { data { diff --git a/packages/portal/src/elements/tables/PeopleTable.tsx b/packages/portal/src/elements/tables/PeopleTable.tsx index abe966ba..c12b4e55 100644 --- a/packages/portal/src/elements/tables/PeopleTable.tsx +++ b/packages/portal/src/elements/tables/PeopleTable.tsx @@ -134,8 +134,8 @@ export const PeopleTable = () => { | "committeeName", direction: sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + ? SortDirection.asc + : SortDirection.desc, }); } clearFilters(); diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index a2cede9e..8445284e 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -69,9 +69,7 @@ export const TeamsTable = () => { { initPage: 1, initPageSize: 20, - initSorting: [ - { field: "totalPoints", direction: SortDirection.DESCENDING }, - ], + initSorting: [{ field: "totalPoints", direction: SortDirection.desc }], }, { allFields: [ @@ -238,9 +236,7 @@ export const TeamsTable = () => { | "legacyStatus" | "marathonYear", direction: - sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + sort.order === "ascend" ? SortDirection.asc : SortDirection.desc, }); } clearFilters(); diff --git a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx index f5aafeeb..ee8a3a9f 100644 --- a/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationDeliveriesTable.tsx @@ -141,8 +141,8 @@ export const NotificationDeliveriesTable = ({ | "deliveryError", direction: sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + ? SortDirection.asc + : SortDirection.desc, }); } diff --git a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx index 28f0a5ac..7dbbdfcc 100644 --- a/packages/portal/src/elements/tables/notification/NotificationsTable.tsx +++ b/packages/portal/src/elements/tables/notification/NotificationsTable.tsx @@ -136,8 +136,8 @@ export const NotificationsTable = () => { field: sort.field as "title" | "body" | "createdAt" | "updatedAt", direction: sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + ? SortDirection.asc + : SortDirection.desc, }); } }} diff --git a/packages/portal/src/pages/events/list-events/EventsTable.tsx b/packages/portal/src/pages/events/list-events/EventsTable.tsx index ff4f3cfd..65286cc0 100644 --- a/packages/portal/src/pages/events/list-events/EventsTable.tsx +++ b/packages/portal/src/pages/events/list-events/EventsTable.tsx @@ -168,8 +168,8 @@ export const EventsTable = () => { | "summary", direction: sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + ? SortDirection.asc + : SortDirection.desc, }); } }} diff --git a/packages/portal/src/pages/images/list/ImagesTable.tsx b/packages/portal/src/pages/images/list/ImagesTable.tsx index a6086812..fbe2474d 100644 --- a/packages/portal/src/pages/images/list/ImagesTable.tsx +++ b/packages/portal/src/pages/images/list/ImagesTable.tsx @@ -65,9 +65,7 @@ export const ImagesTable = () => { { initPage: 1, initPageSize: 10, - initSorting: [ - { field: "createdAt", direction: SortDirection.DESCENDING }, - ], + initSorting: [{ field: "createdAt", direction: SortDirection.desc }], }, { allFields: ["alt", "width", "height", "createdAt", "updatedAt"], @@ -186,8 +184,8 @@ export const ImagesTable = () => { | "updatedAt", direction: sort.order === "ascend" - ? SortDirection.ASCENDING - : SortDirection.DESCENDING, + ? SortDirection.asc + : SortDirection.desc, }); } }} diff --git a/packages/portal/src/pages/people/create-person/CreatePersonPage.tsx b/packages/portal/src/pages/people/create-person/CreatePersonPage.tsx index f6ce14f7..9b9a1a3e 100644 --- a/packages/portal/src/pages/people/create-person/CreatePersonPage.tsx +++ b/packages/portal/src/pages/people/create-person/CreatePersonPage.tsx @@ -5,7 +5,7 @@ import { useQuery } from "urql"; const createPersonPageDocument = graphql(/* GraphQL */ ` query CreatePersonPage { - teams(sendAll: true, sortBy: ["name"], sortDirection: [ASCENDING]) { + teams(sendAll: true, sortBy: ["name"], sortDirection: [asc]) { data { ...TeamNameFragment } diff --git a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx index 5bf971fd..5e4ff9e2 100644 --- a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx +++ b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx @@ -11,7 +11,7 @@ const viewPersonPageDocument = graphql(/* GraphQL */ ` ...PersonEditorFragment } } - teams(sendAll: true, sortBy: ["name"], sortDirection: [ASCENDING]) { + teams(sendAll: true, sortBy: ["name"], sortDirection: [asc]) { data { ...TeamNameFragment } diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index c11944ab..c3dad45d 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -37,24 +37,40 @@ const errorHandlingMiddleware: MiddlewareFn = async (_, next) => { } }; +const resolvers = [ + ConfigurationResolver, + DeviceResolver, + EventResolver, + ImageResolver, + PersonResolver, + MembershipResolver, + NotificationResolver, + NotificationDeliveryResolver, + TeamResolver, + LoginStateResolver, + PointEntryResolver, + PointOpportunityResolver, + MarathonHourResolver, + MarathonResolver, + FeedResolver, +] as const; + +for (const service of resolvers) { + // @ts-expect-error Typedi doesn't seem to like it, but it works + if (!Container.has(service)) { + logger.crit(`Failed to resolve service: "${service.name}"`); + } else { + try { + // @ts-expect-error Typedi doesn't seem to like it, but it works + Container.get(service); + } catch (error) { + logger.crit(`Failed to resolve service: "${service.name}"`, error); + } + } +} + export default await buildSchema({ - resolvers: [ - ConfigurationResolver, - DeviceResolver, - EventResolver, - ImageResolver, - PersonResolver, - MembershipResolver, - NotificationResolver, - NotificationDeliveryResolver, - TeamResolver, - LoginStateResolver, - PointEntryResolver, - PointOpportunityResolver, - MarathonHourResolver, - MarathonResolver, - FeedResolver, - ], + resolvers, emitSchemaFile: schemaPath, globalMiddlewares: [errorHandlingMiddleware], container: Container, diff --git a/packages/server/src/prisma.ts b/packages/server/src/prisma.ts index 182126c9..eaa6f58b 100644 --- a/packages/server/src/prisma.ts +++ b/packages/server/src/prisma.ts @@ -1,4 +1,5 @@ import { PrismaClient } from "@prisma/client"; +import { DetailedError, ErrorCode } from "@ukdanceblue/common"; import { Container } from "typedi"; import { logger } from "./lib/logging/standardLogging.js"; @@ -8,7 +9,10 @@ export const prisma = new PrismaClient(); Container.set(PrismaClient, prisma); if (!Container.has(PrismaClient)) { - throw new Error("PrismaClient not registered"); + throw new DetailedError( + ErrorCode.InternalFailure, + "PrismaClient not registered" + ); } else { logger.info("PrismaClient registered"); } diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index d08ad15d..dddb10c1 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -9,11 +9,9 @@ import { import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - MarathonRepository, - UniqueMarathonParam, -} from "../marathon/MarathonRepository.js"; -import type { MembershipRepository } from "../membership/MembershipRepository.js"; +import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; +import { MarathonRepository } from "../marathon/MarathonRepository.js"; +import { MembershipRepository } from "../membership/MembershipRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import * as CommitteeDescriptions from "./committeeDescriptions.js"; diff --git a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts index 6ab90af2..9b3d7fbc 100644 --- a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts +++ b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts @@ -18,7 +18,7 @@ export function buildCommitteeOrder( case "identifier": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts index 8ea3c72d..71290bfb 100644 --- a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts +++ b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts @@ -21,7 +21,7 @@ export function buildConfigurationOrder( case "validUntil": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/device/deviceRepositoryUtils.ts b/packages/server/src/repositories/device/deviceRepositoryUtils.ts index 2a980bc8..d251ea8f 100644 --- a/packages/server/src/repositories/device/deviceRepositoryUtils.ts +++ b/packages/server/src/repositories/device/deviceRepositoryUtils.ts @@ -19,7 +19,7 @@ export function buildDeviceOrder( case "lastSeen": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/event/EventRepository.ts b/packages/server/src/repositories/event/EventRepository.ts index 1bfd8f88..c85f5fa4 100644 --- a/packages/server/src/repositories/event/EventRepository.ts +++ b/packages/server/src/repositories/event/EventRepository.ts @@ -107,7 +107,7 @@ export class EventRepository { rows.sort((a, b) => { const aDate = a.eventOccurrences[0]?.date ?? new Date(0); const bDate = b.eventOccurrences[0]?.date ?? new Date(0); - return sort === SortDirection.ASCENDING + return sort === SortDirection.asc ? aDate.getTime() - bDate.getTime() : bDate.getTime() - aDate.getTime(); }); @@ -117,7 +117,7 @@ export class EventRepository { rows.sort((a, b) => { const aDate = a.eventOccurrences.at(-1)?.date ?? new Date(0); const bDate = b.eventOccurrences.at(-1)?.date ?? new Date(0); - return sort === SortDirection.ASCENDING + return sort === SortDirection.asc ? aDate.getTime() - bDate.getTime() : bDate.getTime() - aDate.getTime(); }); diff --git a/packages/server/src/repositories/event/eventRepositoryUtils.ts b/packages/server/src/repositories/event/eventRepositoryUtils.ts index 7a13c461..ecc6aed6 100644 --- a/packages/server/src/repositories/event/eventRepositoryUtils.ts +++ b/packages/server/src/repositories/event/eventRepositoryUtils.ts @@ -25,7 +25,7 @@ export function buildEventOrder( case "location": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } case "occurrence": diff --git a/packages/server/src/repositories/image/imageRepositoryUtils.ts b/packages/server/src/repositories/image/imageRepositoryUtils.ts index 8c946947..74ca6df9 100644 --- a/packages/server/src/repositories/image/imageRepositoryUtils.ts +++ b/packages/server/src/repositories/image/imageRepositoryUtils.ts @@ -21,7 +21,7 @@ export function buildImageOrder( case "createdAt": case "alt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts index 5024482c..aea9b9b2 100644 --- a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts +++ b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts @@ -26,7 +26,7 @@ export function buildMarathonOrder( case "endDate": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts index bb6d1a6c..ba093a1d 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts @@ -28,12 +28,12 @@ export function buildMarathonHourOrder( case "shownStartingAt": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } case "marathonYear": { orderBy.marathon = { - year: sort === SortDirection.ASCENDING ? "asc" : "desc", + year: sort === SortDirection.asc ? "asc" : "desc", }; break; } diff --git a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts index ae5167d5..18dc2710 100644 --- a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts +++ b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts @@ -14,7 +14,7 @@ export function buildMembershipOrder( switch (key) { case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts index 9fd9d30d..a72b6b41 100644 --- a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts +++ b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts @@ -30,7 +30,7 @@ export function buildNotificationOrder( case "deliveryIssueAcknowledgedAt": case "sendAt": case "startedSendingAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts index 8d404c38..b7982d63 100644 --- a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts +++ b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts @@ -26,7 +26,7 @@ export function buildNotificationDeliveryOrder( case "deliveryError": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index 32aca3e7..a93e1b3a 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -23,7 +23,7 @@ export function buildPersonOrder( case "linkblue": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/pointEntry/pointEntryRepositoryUtils.ts b/packages/server/src/repositories/pointEntry/pointEntryRepositoryUtils.ts index 771c2338..acf874cd 100644 --- a/packages/server/src/repositories/pointEntry/pointEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/pointEntry/pointEntryRepositoryUtils.ts @@ -12,7 +12,7 @@ export function buildPointEntryOrder( switch (key) { case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts index 18c1e5fd..4a66a0b6 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts @@ -27,7 +27,7 @@ export function buildPointOpportunityOrder( case "type": case "createdAt": case "updatedAt": { - orderBy[key] = sort === SortDirection.ASCENDING ? "asc" : "desc"; + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } default: { diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index 604fcd9b..c82a7cca 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -25,7 +25,7 @@ export function buildTeamOrder( case "createdAt": case "updatedAt": { orderBy.push({ - [key]: sort === SortDirection.ASCENDING ? "asc" : "desc", + [key]: sort === SortDirection.asc ? "asc" : "desc", }); break; } diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index c87ef15d..6652c652 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -103,7 +103,7 @@ export class ConfigurationResolver { @Query(() => GetAllConfigurationsResponse, { name: "allConfigurations" }) async getAll(): Promise { const rows = await this.configurationRepository.findConfigurations(null, [ - ["createdAt", SortDirection.DESCENDING], + ["createdAt", SortDirection.desc], ]); return GetAllConfigurationsResponse.newOk( diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index ce4c4138..426f9628 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -27,7 +27,7 @@ import { auditLogger } from "../lib/logging/auditLogging.js"; import { DeviceRepository } from "../repositories/device/DeviceRepository.js"; import { deviceModelToResource } from "../repositories/device/deviceModelToResource.js"; import { notificationDeliveryModelToResource } from "../repositories/notificationDelivery/notificationDeliveryModelToResource.js"; -import type { PersonRepository } from "../repositories/person/PersonRepository.js"; +import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { @@ -144,7 +144,7 @@ export class DeviceResolver { orderBy: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index 80745cfa..593c6810 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -222,7 +222,7 @@ export class EventResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index 62461703..7f5b9cba 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -108,7 +108,7 @@ export class ImageResolver { order: args.sortBy?.map((key, i) => [ key, - args.sortDirection?.[i] ?? SortDirection.DESCENDING, + args.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: args.page != null && args.pageSize != null diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 0a46f6ed..eb32c8b0 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -24,7 +24,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import type { CommitteeRepository } from "../repositories/committee/CommitteeRepository.js"; +import { CommitteeRepository } from "../repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; import { marathonHourModelToResource } from "../repositories/marathonHour/marathonHourModelToResource.js"; @@ -121,7 +121,7 @@ export class MarathonResolver order: args.sortBy?.map((key, i) => [ key, - args.sortDirection?.[i] ?? SortDirection.DESCENDING, + args.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: args.page != null && args.pageSize != null diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 048fe58c..5ec5e618 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -9,7 +9,7 @@ import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; -import type { PersonRepository } from "../repositories/person/PersonRepository.js"; +import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 5c3be01d..865faade 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -257,7 +257,7 @@ export class NotificationResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null @@ -294,7 +294,7 @@ export class NotificationResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 6652468c..ad09152c 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -30,7 +30,7 @@ import { import { Service } from "typedi"; import { auditLogger } from "../lib/logging/auditLogging.js"; -import type { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; +import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { committeeMembershipModelToResource, membershipModelToResource, @@ -199,7 +199,7 @@ export class PersonResolver { order: args.sortBy?.map((key, i) => [ key, - args.sortDirection?.[i] ?? SortDirection.DESCENDING, + args.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: args.page != null && args.pageSize != null diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index f9ff6969..b7a033fd 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -24,7 +24,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import type { PersonRepository } from "../repositories/person/PersonRepository.js"; +import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { PointEntryRepository } from "../repositories/pointEntry/PointEntryRepository.js"; import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; @@ -127,7 +127,7 @@ export class PointEntryResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index d3a325e0..c3175591 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -140,7 +140,7 @@ export class PointOpportunityResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 4525a996..0dc420ec 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -161,7 +161,7 @@ export class TeamResolver { order: query.sortBy?.map((key, i) => [ key, - query.sortDirection?.[i] ?? SortDirection.DESCENDING, + query.sortDirection?.[i] ?? SortDirection.desc, ]) ?? [], skip: query.page != null && query.pageSize != null diff --git a/schema.graphql b/schema.graphql index 338e0508..95c71421 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1862,8 +1862,8 @@ type SingleTeamResponse implements AbstractGraphQLOkResponse & GraphQLBaseRespon } enum SortDirection { - ASCENDING - DESCENDING + asc + desc } type StageNotificationResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { From a6ab3a9f8d183e6f3d1bbdd7443fc571604f7f79 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 27 May 2024 01:51:33 +0000 Subject: [PATCH 061/153] Refactor TeamsTable to integrate marathon filter with global setting --- .../portal/src/elements/tables/TeamsTable.tsx | 14 ++++++++ packages/server/src/lib/logging/sqlLogging.ts | 25 ++++++++++++- packages/server/src/prisma.ts | 35 ++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index 8445284e..b7d6bee6 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -9,6 +9,7 @@ import { graphql, } from "@ukdanceblue/common/graphql-client-admin"; import { Button, Flex, Table } from "antd"; +import { useEffect } from "react"; import { useQuery } from "urql"; const teamsTableQueryDocument = graphql(/* GraphQL */ ` @@ -97,6 +98,19 @@ export const TeamsTable = () => { loadingMessage: "Loading teams...", }); + useEffect(() => { + if ( + queryOptions.oneOfFilters.filter((f) => f.field === "marathonYear") + .length === 0 + ) { + // TODO: Extract the marathon filter from the table and integrate it with a global setting for marathon + updateFilter("marathonYear", { + field: "marathonYear", + value: ["DB24"], + }); + } + }, [queryOptions.oneOfFilters, updateFilter]); + return (
    { + sqlLogger.sql(e.query); +}); +prisma.$on("info", (e) => { + sqlLogger.info(e.message); +}); +prisma.$on("warn", (e) => { + sqlLogger.warning(e.message); +}); +prisma.$on("error", (e) => { + sqlLogger.error(e.message); +}); Container.set(PrismaClient, prisma); From 0806b6b92c5e714b7170fb69a6abaa0119f0d160 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 27 May 2024 02:43:30 +0000 Subject: [PATCH 062/153] Refactor LoginStateResolver to use userData.authSource for determining login state --- packages/server/src/resolvers/LoginState.ts | 2 +- packages/server/src/resolvers/context.ts | 215 +++++++++----------- 2 files changed, 100 insertions(+), 117 deletions(-) diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index d6cc709a..d6f72b94 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -29,7 +29,7 @@ export class LoginStateResolver { @Query(() => LoginState) loginState(@Ctx() ctx: Context.GraphQLContext): LoginState { return { - loggedIn: ctx.authenticatedUser != null, + loggedIn: ctx.userData.authSource !== AuthSource.None, effectiveCommitteeRoles: ctx.effectiveCommitteeRoles, dbRole: ctx.authorization.dbRole, authSource: ctx.userData.authSource, diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 02455a92..885c6b22 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -23,6 +23,19 @@ export const graphqlContextFunction: ContextFunction< [KoaContextFunctionArgument], GraphQLContext > = async ({ ctx }): Promise => { + // Set up the context object + const context: GraphQLContext = { + authenticatedUser: null, + effectiveCommitteeRoles: [], + teamMemberships: [], + userData: { + authSource: AuthSource.None, + }, + authorization: defaultAuthorization, + contextErrors: [], + }; + + // Get the token from the cookies or the Authorization header let token = ctx.cookies.get("token"); if (!token) { const authorizationHeader = ctx.get("Authorization"); @@ -31,132 +44,102 @@ export const graphqlContextFunction: ContextFunction< } } if (!token) { - return { - authenticatedUser: null, - effectiveCommitteeRoles: [], - teamMemberships: [], - userData: { - authSource: AuthSource.None, - }, - authorization: defaultAuthorization, - contextErrors: [], - }; + // Short-circuit if no token is present + return context; } + + // Parse the token const { userId, authSource } = parseUserJwt(token); - if (!userId) { - logger.trace("graphqlContextFunction No userId found"); - return { - authenticatedUser: null, - effectiveCommitteeRoles: [], - teamMemberships: [], - userData: { - authSource, - }, - authorization: defaultAuthorization, - contextErrors: [], - }; - } + // Set the auth source + context.userData.authSource = authSource; - const personRepository = Container.get(PersonRepository); - const person = await personRepository.findPersonAndTeamsByUnique({ - uuid: userId, - }); + // Set the dbRole based on the auth source + if (authSource === AuthSource.LinkBlue || authSource === AuthSource.Demo) { + context.authorization.dbRole = DbRole.UKY; + } else if (authSource === AuthSource.Anonymous) { + context.authorization.dbRole = DbRole.Public; + } - if (person) { - const personResource = await personModelToResource( - person, - personRepository - ); - logger.trace("graphqlContextFunction Found user", personResource); + // If we have a user ID, look up the user + if (userId) { + const personRepository = Container.get(PersonRepository); + const person = await personRepository.findPersonAndTeamsByUnique({ + uuid: userId, + }); - const memberships = await personRepository.findCommitteeMembershipsOfPerson( - { id: person.id } - ); - const committees = - memberships - ?.map((membership) => - membership.team.correspondingCommittee - ? { - identifier: membership.team.correspondingCommittee.identifier, - role: membership.committeeRole ?? CommitteeRole.Member, - } - : undefined - ) - .filter( - (committee): committee is NonNullable => - committee != null - ) ?? []; - logger.trace("graphqlContextFunction Found committees", ...committees); + // If we found a user, set the authenticated user + if (person) { + // Convert the user to a resource and set it on the context + const personResource = await personModelToResource( + person, + personRepository + ); + logger.trace("graphqlContextFunction Found user", personResource); + context.authenticatedUser = personResource; - const teamMemberships = - (await personRepository.findMembershipsOfPerson( - { + // Set the committees the user is on + const committeeMemberships = + await personRepository.findCommitteeMembershipsOfPerson({ id: person.id, - }, - {}, - undefined, - true - )) ?? []; - logger.trace( - "graphqlContextFunction Found team memberships", - ...teamMemberships - ); - - const effectiveCommitteeRoles = - await personRepository.getEffectiveCommitteeRolesOfPerson({ - id: person.id, - }); - logger.trace( - "graphqlContextFunction Effective committee roles", - ...effectiveCommitteeRoles - ); - - let dbRole: DbRole; - if (effectiveCommitteeRoles.length > 0) { - dbRole = DbRole.Committee; - } else if ( - authSource === AuthSource.LinkBlue || - authSource === AuthSource.Demo - ) { - dbRole = DbRole.UKY; - } else if (authSource === AuthSource.Anonymous) { - dbRole = DbRole.Public; - } else { - dbRole = DbRole.None; - } - - logger.trace("graphqlContextFunction", { dbRole }); + }); + const committees = + committeeMemberships + ?.map((membership) => + membership.team.correspondingCommittee + ? { + identifier: membership.team.correspondingCommittee.identifier, + role: membership.committeeRole ?? CommitteeRole.Member, + } + : undefined + ) + .filter( + (committee): committee is NonNullable => + committee != null + ) ?? []; + logger.trace("graphqlContextFunction Found committees", ...committees); + context.authorization.committees = committees; - return { - authenticatedUser: personResource, - effectiveCommitteeRoles, - teamMemberships: teamMemberships.map((membership) => ({ + // Set the teams the user is on + const teamMemberships = + (await personRepository.findMembershipsOfPerson( + { + id: person.id, + }, + {}, + undefined, + true + )) ?? []; + logger.trace( + "graphqlContextFunction Found team memberships", + ...teamMemberships + ); + context.teamMemberships = teamMemberships.map((membership) => ({ teamType: membership.team.type, position: membership.position, teamId: membership.team.uuid, - })), - userData: { - userId, - authSource, - }, - authorization: { - committees, - dbRole, - accessLevel: roleToAccessLevel({ dbRole, committees }), - }, - contextErrors: [], - }; - } else { - logger.trace("graphqlContextFunction User not found"); - return { - authenticatedUser: null, - effectiveCommitteeRoles: [], - teamMemberships: [], - userData: { - authSource: AuthSource.None, - }, - authorization: defaultAuthorization, - contextErrors: ["User not found"], - }; + })); + + // Set the effective committee roles the user has + const effectiveCommitteeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ + id: person.id, + }); + logger.trace( + "graphqlContextFunction Effective committee roles", + ...effectiveCommitteeRoles + ); + context.effectiveCommitteeRoles = effectiveCommitteeRoles; + + // If the user is on a committee, override the dbRole + if (effectiveCommitteeRoles.length > 0) { + context.authorization.dbRole = DbRole.Committee; + } + } } + + context.authorization.accessLevel = roleToAccessLevel(context.authorization); + + logger.trace("graphqlContextFunction Context", context); + + return context; }; From e67e1549a2b5912cafd9fd3ab7a59ebba945c17e Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 06:01:43 +0000 Subject: [PATCH 063/153] Add database tables and foreign key constraints for fundraising entries and assignments --- .../20240529060132_dbfunds_sync/migration.sql | 99 +++++++++++++++++ packages/server/prisma/schema.prisma | 105 ++++++++++++++++-- 2 files changed, 192 insertions(+), 12 deletions(-) create mode 100644 packages/server/prisma/migrations/20240529060132_dbfunds_sync/migration.sql diff --git a/packages/server/prisma/migrations/20240529060132_dbfunds_sync/migration.sql b/packages/server/prisma/migrations/20240529060132_dbfunds_sync/migration.sql new file mode 100644 index 00000000..a99b90c9 --- /dev/null +++ b/packages/server/prisma/migrations/20240529060132_dbfunds_sync/migration.sql @@ -0,0 +1,99 @@ +/* + Warnings: + + - A unique constraint covering the columns `[db_funds_team_id]` on the table `teams` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "teams" ADD COLUMN "db_funds_team_id" INTEGER; + +-- CreateTable +CREATE TABLE "db_funds_teams" ( + "id" SERIAL NOT NULL, + "db_num" INTEGER NOT NULL, + "name" TEXT NOT NULL, + "total_amount" DOUBLE PRECISION NOT NULL, + "active" BOOLEAN NOT NULL, + + CONSTRAINT "db_funds_teams_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "db_funds_team_entries" ( + "id" SERIAL NOT NULL, + "amount" DECIMAL(65,30) NOT NULL, + "donated_by" TEXT NOT NULL, + "donated_to" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "team_db_num" INTEGER NOT NULL, + + CONSTRAINT "db_funds_team_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "fundraising_entries" ( + "id" SERIAL NOT NULL, + "uuid" UUID NOT NULL, + "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) NOT NULL, + "total_amount" DECIMAL(65,30) NOT NULL, + "db_funds_entry_donated_by" TEXT, + "db_funds_entry_date" TIMESTAMP(3), + + CONSTRAINT "fundraising_entries_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "fundraising_assignments" ( + "id" SERIAL NOT NULL, + "uuid" UUID NOT NULL, + "created_at" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMPTZ(6) NOT NULL, + "amount" DECIMAL(65,30) NOT NULL, + "person_id" INTEGER NOT NULL, + "fundraising_id" INTEGER NOT NULL, + + CONSTRAINT "fundraising_assignments_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "db_funds_teams_db_num_key" ON "db_funds_teams"("db_num"); + +-- CreateIndex +CREATE UNIQUE INDEX "db_funds_team_entries_donated_by_date_key" ON "db_funds_team_entries"("donated_by", "date"); + +-- CreateIndex +CREATE UNIQUE INDEX "fundraising_entries_uuid_unique" ON "fundraising_entries"("uuid"); + +-- CreateIndex +CREATE INDEX "fundraising_entries_uuid" ON "fundraising_entries"("uuid"); + +-- CreateIndex +CREATE UNIQUE INDEX "fundraising_entries_db_funds_entry_donated_by_date_key" ON "fundraising_entries"("db_funds_entry_donated_by", "db_funds_entry_date"); + +-- CreateIndex +CREATE UNIQUE INDEX "fundraising_assignments_uuid_unique" ON "fundraising_assignments"("uuid"); + +-- CreateIndex +CREATE INDEX "fundraising_assignments_uuid" ON "fundraising_assignments"("uuid"); + +-- CreateIndex +CREATE UNIQUE INDEX "fundraising_assignments_fundraising_id_person_id_key" ON "fundraising_assignments"("fundraising_id", "person_id"); + +-- CreateIndex +CREATE UNIQUE INDEX "teams_db_funds_team_id_key" ON "teams"("db_funds_team_id"); + +-- AddForeignKey +ALTER TABLE "teams" ADD CONSTRAINT "teams_db_funds_team_id_fkey" FOREIGN KEY ("db_funds_team_id") REFERENCES "db_funds_teams"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "db_funds_team_entries" ADD CONSTRAINT "db_funds_team_entries_team_db_num_fkey" FOREIGN KEY ("team_db_num") REFERENCES "db_funds_teams"("db_num") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "fundraising_entries" ADD CONSTRAINT "fundraising_entries_db_funds_entry_donated_by_db_funds_ent_fkey" FOREIGN KEY ("db_funds_entry_donated_by", "db_funds_entry_date") REFERENCES "db_funds_team_entries"("donated_by", "date") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "fundraising_assignments" ADD CONSTRAINT "fundraising_assignments_person_id_fkey" FOREIGN KEY ("person_id") REFERENCES "people"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "fundraising_assignments" ADD CONSTRAINT "fundraising_assignments_fundraising_id_fkey" FOREIGN KEY ("fundraising_id") REFERENCES "fundraising_entries"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index b28a846b..52d56b8c 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -167,18 +167,19 @@ model Membership { } model Person { - id Int @id @default(autoincrement()) - uuid String @unique(map: "people_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - name String? - email String @unique(map: "people_email_unique") - linkblue String? @unique(map: "people_linkblue_unique") - authIdPairs AuthIdPair[] - devices Device[] - memberships Membership[] - pointEntries PointEntry[] - ownedFiles File[] + id Int @id @default(autoincrement()) + uuid String @unique(map: "people_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + name String? + email String @unique(map: "people_email_unique") + linkblue String? @unique(map: "people_linkblue_unique") + authIdPairs AuthIdPair[] + devices Device[] + memberships Membership[] + pointEntries PointEntry[] + ownedFiles File[] + assignedFundraisingEntries FundraisingAssignment[] @@index([uuid], map: "people_uuid") @@map("people") @@ -241,6 +242,8 @@ model Team { pointEntries PointEntry[] correspondingCommittee Committee? @relation(fields: [correspondingCommitteeId], references: [id]) correspondingCommitteeId Int? @map("committee_id") + dbFundsTeam DBFundsTeam? @relation(fields: [dbFundsTeamId], references: [id]) + dbFundsTeamId Int? @unique @map("db_funds_team_id") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) @@ -398,6 +401,84 @@ model FeedItem { @@map("feed_items") } +// This table is kept in sync with the DBFunds API and should not be modified +model DBFundsTeam { + // Unrelated to the 'id' field in the DBFunds API + id Int @id @default(autoincrement()) + // The team's DbNum from the DBFunds API + dbNum Int @unique @map("db_num") + // The team's name from the DBFunds API + name String + // The team's total fundraising amount from the DBFunds API + totalAmount Float @map("total_amount") + // Whether the team is active in DBFunds + active Boolean + // All fundraising entries for the team + fundraisingEntries DBFundsFundraisingEntry[] + + // The corresponding team in our database + team Team? + + @@map("db_funds_teams") +} + +// This table is kept in sync with the DBFunds API and should not be modified +model DBFundsFundraisingEntry { + // Unrelated to the 'id' field in the DBFunds API + id Int @id @default(autoincrement()) + // The amount of the entry + amount Decimal + // Who made the donation + donatedBy String @map("donated_by") + // Who the donation was made for + donatedTo String @map("donated_to") + // The date of the donation + date DateTime + // The team's DbNum from the DBFunds API + teamDbNum Int @map("team_db_num") + team DBFundsTeam @relation(fields: [teamDbNum], references: [dbNum]) + + // The corresponding fundraising entry in our database + fundraisingEntry FundraisingEntry? + + @@unique([donatedBy, date], map: "db_funds_team_entries_donated_by_date_key") + @@map("db_funds_team_entries") +} + +model FundraisingEntry { + id Int @id @default(autoincrement()) + uuid String @unique(map: "fundraising_entries_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + totalAmount Decimal @map("total_amount") + + dbFundsEntry DBFundsFundraisingEntry? @relation(references: [donatedBy, date], fields: [dbFundsEntryDonatedBy, dbFundsEntryDate]) + dbFundsEntryDonatedBy String? @map("db_funds_entry_donated_by") + dbFundsEntryDate DateTime? @map("db_funds_entry_date") + + assignments FundraisingAssignment[] + + @@unique([dbFundsEntryDonatedBy, dbFundsEntryDate], map: "fundraising_entries_db_funds_entry_donated_by_date_key") + @@index([uuid], map: "fundraising_entries_uuid") + @@map("fundraising_entries") +} + +model FundraisingAssignment { + id Int @id @default(autoincrement()) + uuid String @unique(map: "fundraising_assignments_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) + amount Decimal + personId Int @map("person_id") + person Person @relation(fields: [personId], references: [id]) + parentEntry FundraisingEntry @relation(fields: [fundraisingId], references: [id]) + fundraisingId Int @map("fundraising_id") + + @@unique([fundraisingId, personId], map: "fundraising_assignments_fundraising_id_person_id_key") + @@index([uuid], map: "fundraising_assignments_uuid") + @@map("fundraising_assignments") +} + // Potential errors after sending a notification to Expo (see https://docs.expo.dev/push-notifications/sending-notifications/#individual-errors) enum NotificationError { // The device cannot receive push notifications anymore and you should stop sending messages to the corresponding Expo push token. From 5dbcd2b6438760db4bb57059f2c1c6b6cfe84b2d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 06:05:37 +0000 Subject: [PATCH 064/153] Connect demoTeam by id in PersonRepository --- .../server/src/repositories/person/PersonRepository.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 6715de3d..1133d8ab 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -580,7 +580,9 @@ export class PersonRepository { memberships: { create: { team: { - connect: demoTeam, + connect: { + id: demoTeam.id, + }, }, position: MembershipPositionType.Captain, }, @@ -588,7 +590,9 @@ export class PersonRepository { pointEntries: { create: { team: { - connect: demoTeam, + connect: { + id: demoTeam.id, + }, }, points: 1, comment: "Demo point", From 09fca934bfdf554343d8a05113ded7228a03d7d4 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 06:05:43 +0000 Subject: [PATCH 065/153] Update npm dependencies --- packages/server/package.json | 1 + yarn.lock | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/packages/server/package.json b/packages/server/package.json index 1addc86b..156c3961 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -54,6 +54,7 @@ "croner": "^8.0.1", "dotenv": "^16.0.3", "dree": "^4.5.2", + "effect": "^3.2.5", "ejs": "^3.1.9", "expo-server-sdk": "^3.7.0", "express": "^4.18.2", diff --git a/yarn.lock b/yarn.lock index b70faefe..86d12fd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8708,6 +8708,7 @@ __metadata: croner: "npm:^8.0.1" dotenv: "npm:^16.0.3" dree: "npm:^4.5.2" + effect: "npm:^3.2.5" ejs: "npm:^3.1.9" expo-server-sdk: "npm:^3.7.0" express: "npm:^4.18.2" @@ -12768,6 +12769,13 @@ __metadata: languageName: node linkType: hard +"effect@npm:^3.2.5": + version: 3.2.5 + resolution: "effect@npm:3.2.5" + checksum: 10/7d5c92f102f87de13ce6c689981a98c78b0ef2cbe5ea370732c60a8049995d9ddda77943ae3049216db29eb9f307b09bccaaee05e40b04b77a6ecf1648544163 + languageName: node + linkType: hard + "ejs@npm:^3.1.5, ejs@npm:^3.1.6, ejs@npm:^3.1.7, ejs@npm:^3.1.8, ejs@npm:^3.1.9": version: 3.1.9 resolution: "ejs@npm:3.1.9" From d8aab0aeb762486d79b9c3733276e21ccef67b7b Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 06:36:39 +0000 Subject: [PATCH 066/153] Remove old packages and add true-myth --- packages/server/package.json | 27 +-- packages/server/tsconfig.json | 18 +- yarn.lock | 341 +++------------------------------- 3 files changed, 32 insertions(+), 354 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 156c3961..db04247b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -27,50 +27,30 @@ "@as-integrations/koa": "^1.1.1", "@azure/msal-node": "^1.16.0", "@faker-js/faker": "^7.6.0", - "@jest/globals": "^29.5.0", "@koa/cors": "^4.0.0", "@koa/router": "^12.0.1", "@prisma/client": "^5.8.0", - "@types/body-parser": "^1.19.2", - "@types/cookie-parser": "^1.4.3", - "@types/cors": "^2.8.13", - "@types/ejs": "^3.1.2", - "@types/express": "^4.17.17", "@types/express-session": "^1.17.7", "@types/http-errors": "^2.0.1", "@types/jsonwebtoken": "^9.0.1", "@types/luxon": "^3.4.2", - "@types/multer": "^1.4.7", "@types/node": "^18.15.11", "@types/node-fetch": "^2.6.4", "@types/normalize-path": "^3.0.0", - "@types/qs": "^6.9.7", - "@types/ws": "^8.5.4", "@ukdanceblue/common": "workspace:^", - "body-parser": "^1.20.2", "class-validator": "^0.14.0", - "cookie-parser": "^1.4.6", - "cors": "^2.8.5", "croner": "^8.0.1", "dotenv": "^16.0.3", "dree": "^4.5.2", - "effect": "^3.2.5", - "ejs": "^3.1.9", "expo-server-sdk": "^3.7.0", - "express": "^4.18.2", - "express-session": "^1.17.3", "graphql": "^16.8.0", "graphql-scalars": "^1.22.5", - "http-errors": "^2.0.0", "http-status-codes": "^2.2.0", - "jest": "^29.5.0", - "joi": "^17.9.1", "jsonwebtoken": "^9.0.0", "koa": "^2.14.2", "koa-body": "^6.0.1", "luxon": "^3.4.4", "mime": "^4.0.1", - "multer": "1.4.5-lts.1", "node-fetch": "^3.3.1", "normalize-path": "^3.0.0", "openid-client": "^5.4.0", @@ -78,20 +58,17 @@ "pg-hstore": "^2.3.4", "postgres-interval": "^4.0.0", "postgres-range": "^1.1.3", - "qs": "^6.11.1", "reflect-metadata": "^0.2.1", "sharp": "^0.32.1", "thumbhash": "^0.1.1", - "ts-jest": "^29.0.5", + "true-myth": "^7.3.0", "ts-node": "^10.9.1", "type-graphql": "^2.0.0-beta.3", "typedi": "^0.10.0", "typescript": "^5.4.3", - "umzug": "^3.3.1", "utility-types": "^3.10.0", "validator": "^13.9.0", - "winston": "^3.8.2", - "ws": "^8.13.0" + "winston": "^3.8.2" }, "devDependencies": { "@types/koa": "^2.13.6", diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 3e959a5e..a781f7ab 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -12,23 +12,7 @@ "allowJs": true, "checkJs": true, "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "types": [ - "body-parser", - "cookie-parser", - "cors", - "ejs", - "express", - "express-session", - "http-errors", - "jsonwebtoken", - "luxon", - "multer", - "node-fetch", - "normalize-path", - "qs", - "ws" - ] + "experimentalDecorators": true }, "include": ["src"], "extends": "../../tsconfig.json" diff --git a/yarn.lock b/yarn.lock index 86d12fd3..47a5c3ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6994,52 +6994,6 @@ __metadata: languageName: node linkType: hard -"@rushstack/node-core-library@npm:4.0.2": - version: 4.0.2 - resolution: "@rushstack/node-core-library@npm:4.0.2" - dependencies: - fs-extra: "npm:~7.0.1" - import-lazy: "npm:~4.0.0" - jju: "npm:~1.4.0" - resolve: "npm:~1.22.1" - semver: "npm:~7.5.4" - z-schema: "npm:~5.0.2" - peerDependencies: - "@types/node": "*" - peerDependenciesMeta: - "@types/node": - optional: true - checksum: 10/d28ba48e4cb755f39ccc9050f0bbc2cdabe7e706b2e7ee2f7dd2c851129f2198e024c2b1f3b5932a0689c9b86d07ae72e58a6bd62f9349f398dbbcf85d399b85 - languageName: node - linkType: hard - -"@rushstack/terminal@npm:0.10.0": - version: 0.10.0 - resolution: "@rushstack/terminal@npm:0.10.0" - dependencies: - "@rushstack/node-core-library": "npm:4.0.2" - supports-color: "npm:~8.1.1" - peerDependencies: - "@types/node": "*" - peerDependenciesMeta: - "@types/node": - optional: true - checksum: 10/4fb496558f4bf03235a6716fac3bbdefa92209c8ba05838b34b8986eaec59961938cb7b3ae5e7dfa4d96b692696291894b0cb7090d76ff29753e8c54624e5343 - languageName: node - linkType: hard - -"@rushstack/ts-command-line@npm:^4.12.2": - version: 4.19.1 - resolution: "@rushstack/ts-command-line@npm:4.19.1" - dependencies: - "@rushstack/terminal": "npm:0.10.0" - "@types/argparse": "npm:1.0.38" - argparse: "npm:~1.0.9" - string-argv: "npm:~0.3.1" - checksum: 10/b529e5ea287369d837066a40689ac501b768c07fcb2af0e291d804d1ba885707742d674be34ec2b77173b8ac3b2e69d9296015412dcf582dbec6d9c5abd49ff8 - languageName: node - linkType: hard - "@segment/ajv-human-errors@npm:^2.1.2": version: 2.12.0 resolution: "@segment/ajv-human-errors@npm:2.12.0" @@ -7473,13 +7427,6 @@ __metadata: languageName: node linkType: hard -"@types/argparse@npm:1.0.38": - version: 1.0.38 - resolution: "@types/argparse@npm:1.0.38" - checksum: 10/26ed7e3f1e3595efdb883a852f5205f971b798e4c28b7e30a32c5298eee596e8b45834ce831f014d250b9730819ab05acff5b31229666d3af4ba465b4697d0eb - languageName: node - linkType: hard - "@types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -7521,7 +7468,7 @@ __metadata: languageName: node linkType: hard -"@types/body-parser@npm:*, @types/body-parser@npm:^1.19.2": +"@types/body-parser@npm:*": version: 1.19.5 resolution: "@types/body-parser@npm:1.19.5" dependencies: @@ -7587,15 +7534,6 @@ __metadata: languageName: node linkType: hard -"@types/cookie-parser@npm:^1.4.3": - version: 1.4.7 - resolution: "@types/cookie-parser@npm:1.4.7" - dependencies: - "@types/express": "npm:*" - checksum: 10/7b87c59420598e686a57e240be6e0db53967c3c8814be9326bf86609ee2fc39c4b3b9f2263e1deba43526090121d1df88684b64c19f7b494a80a4437caf3d40b - languageName: node - linkType: hard - "@types/cookies@npm:*": version: 0.9.0 resolution: "@types/cookies@npm:0.9.0" @@ -7608,15 +7546,6 @@ __metadata: languageName: node linkType: hard -"@types/cors@npm:^2.8.13": - version: 2.8.17 - resolution: "@types/cors@npm:2.8.17" - dependencies: - "@types/node": "npm:*" - checksum: 10/469bd85e29a35977099a3745c78e489916011169a664e97c4c3d6538143b0a16e4cc72b05b407dc008df3892ed7bf595f9b7c0f1f4680e169565ee9d64966bde - languageName: node - linkType: hard - "@types/debug@npm:^4.0.0": version: 4.1.12 resolution: "@types/debug@npm:4.1.12" @@ -7626,13 +7555,6 @@ __metadata: languageName: node linkType: hard -"@types/ejs@npm:^3.1.2": - version: 3.1.5 - resolution: "@types/ejs@npm:3.1.5" - checksum: 10/918898fd279108087722c1713e2ddb0c152ab839397946d164db8a18b5bbd732af9746373882a9bcf4843d35c6b191a8f569a7a4e51e90726d24501b39f40367 - languageName: node - linkType: hard - "@types/eslint-config-prettier@npm:^6.11.3": version: 6.11.3 resolution: "@types/eslint-config-prettier@npm:6.11.3" @@ -7687,7 +7609,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^4.17.13, @types/express@npm:^4.17.17": +"@types/express@npm:*, @types/express@npm:^4.17.13": version: 4.17.21 resolution: "@types/express@npm:4.17.21" dependencies: @@ -7994,15 +7916,6 @@ __metadata: languageName: node linkType: hard -"@types/multer@npm:^1.4.7": - version: 1.4.11 - resolution: "@types/multer@npm:1.4.11" - dependencies: - "@types/express": "npm:*" - checksum: 10/5abbc9a8b0d7bb817a52429c52f052152ebe2fb212e7138359c0c0b9207486ef7b1e54f65915c968300a0874cee546dbfc850415584fc9d14eff2b27bb926e7f - languageName: node - linkType: hard - "@types/node-fetch@npm:^2.6.1, @types/node-fetch@npm:^2.6.4": version: 2.6.11 resolution: "@types/node-fetch@npm:2.6.11" @@ -8070,7 +7983,7 @@ __metadata: languageName: node linkType: hard -"@types/qs@npm:*, @types/qs@npm:^6.9.7": +"@types/qs@npm:*": version: 6.9.14 resolution: "@types/qs@npm:6.9.14" checksum: 10/d3b76021d36b86c0063ec4b7373e9fa470754914e486fbfe54b3a8866dad037800a2c2068ecbcaa9399ae3ed15772a26b07e67793ed2519cf2de199104014716 @@ -8208,7 +8121,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.0.0, @types/ws@npm:^8.5.4": +"@types/ws@npm:^8.0.0": version: 8.5.10 resolution: "@types/ws@npm:8.5.10" dependencies: @@ -8676,15 +8589,9 @@ __metadata: "@as-integrations/koa": "npm:^1.1.1" "@azure/msal-node": "npm:^1.16.0" "@faker-js/faker": "npm:^7.6.0" - "@jest/globals": "npm:^29.5.0" "@koa/cors": "npm:^4.0.0" "@koa/router": "npm:^12.0.1" "@prisma/client": "npm:^5.8.0" - "@types/body-parser": "npm:^1.19.2" - "@types/cookie-parser": "npm:^1.4.3" - "@types/cors": "npm:^2.8.13" - "@types/ejs": "npm:^3.1.2" - "@types/express": "npm:^4.17.17" "@types/express-session": "npm:^1.17.7" "@types/http-errors": "npm:^2.0.1" "@types/jsonwebtoken": "npm:^9.0.1" @@ -8693,38 +8600,24 @@ __metadata: "@types/koa__cors": "npm:^4.0.0" "@types/koa__router": "npm:^12.0.4" "@types/luxon": "npm:^3.4.2" - "@types/multer": "npm:^1.4.7" "@types/node": "npm:^18.15.11" "@types/node-fetch": "npm:^2.6.4" "@types/normalize-path": "npm:^3.0.0" "@types/pg": "npm:^8.6.6" - "@types/qs": "npm:^6.9.7" - "@types/ws": "npm:^8.5.4" "@ukdanceblue/common": "workspace:^" - body-parser: "npm:^1.20.2" class-validator: "npm:^0.14.0" - cookie-parser: "npm:^1.4.6" - cors: "npm:^2.8.5" croner: "npm:^8.0.1" dotenv: "npm:^16.0.3" dree: "npm:^4.5.2" - effect: "npm:^3.2.5" - ejs: "npm:^3.1.9" expo-server-sdk: "npm:^3.7.0" - express: "npm:^4.18.2" - express-session: "npm:^1.17.3" graphql: "npm:^16.8.0" graphql-scalars: "npm:^1.22.5" - http-errors: "npm:^2.0.0" http-status-codes: "npm:^2.2.0" - jest: "npm:^29.5.0" - joi: "npm:^17.9.1" jsonwebtoken: "npm:^9.0.0" koa: "npm:^2.14.2" koa-body: "npm:^6.0.1" luxon: "npm:^3.4.4" mime: "npm:^4.0.1" - multer: "npm:1.4.5-lts.1" node-fetch: "npm:^3.3.1" nodemon: "npm:^2.0.22" normalize-path: "npm:^3.0.0" @@ -8734,21 +8627,18 @@ __metadata: postgres-interval: "npm:^4.0.0" postgres-range: "npm:^1.1.3" prisma: "npm:^5.8.0" - qs: "npm:^6.11.1" reflect-metadata: "npm:^0.2.1" sharp: "npm:^0.32.1" thumbhash: "npm:^0.1.1" - ts-jest: "npm:^29.0.5" + true-myth: "npm:^7.3.0" ts-node: "npm:^10.9.1" type-graphql: "npm:^2.0.0-beta.3" typedi: "npm:^0.10.0" typescript: "npm:^5.4.3" - umzug: "npm:^3.3.1" utility-types: "npm:^3.10.0" validator: "npm:^13.9.0" vitest: "npm:^1.4.0" winston: "npm:^3.8.2" - ws: "npm:^8.13.0" languageName: unknown linkType: soft @@ -9427,13 +9317,6 @@ __metadata: languageName: node linkType: hard -"append-field@npm:^1.0.0": - version: 1.0.0 - resolution: "append-field@npm:1.0.0" - checksum: 10/afb50f5ff668af1cb66bc5cfebb55ed9a1d99e24901782ee83d00aed1a499835f9375a149cf27b17f79595ecfcc3d1de0cd5b020b210a5359c43eaf607c217de - languageName: node - linkType: hard - "application-config-path@npm:^0.1.0": version: 0.1.1 resolution: "application-config-path@npm:0.1.1" @@ -9469,7 +9352,7 @@ __metadata: languageName: node linkType: hard -"argparse@npm:^1.0.7, argparse@npm:~1.0.9": +"argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" dependencies: @@ -10431,7 +10314,7 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.2, body-parser@npm:^1.20.2": +"body-parser@npm:1.20.2": version: 1.20.2 resolution: "body-parser@npm:1.20.2" dependencies: @@ -10666,7 +10549,7 @@ __metadata: languageName: node linkType: hard -"busboy@npm:^1.0.0, busboy@npm:^1.6.0": +"busboy@npm:^1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" dependencies: @@ -11628,18 +11511,6 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.2": - version: 1.6.2 - resolution: "concat-stream@npm:1.6.2" - dependencies: - buffer-from: "npm:^1.0.0" - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.2.2" - typedarray: "npm:^0.0.6" - checksum: 10/71db903c84fc073ca35a274074e8d26c4330713d299f8623e993c448c1f6bf8b967806dd1d1a7b0f8add6f15ab1af7435df21fe79b4fe7efd78420c89e054e28 - languageName: node - linkType: hard - "connect@npm:^3.6.5, connect@npm:^3.7.0": version: 3.7.0 resolution: "connect@npm:3.7.0" @@ -11693,16 +11564,6 @@ __metadata: languageName: node linkType: hard -"cookie-parser@npm:^1.4.6": - version: 1.4.6 - resolution: "cookie-parser@npm:1.4.6" - dependencies: - cookie: "npm:0.4.1" - cookie-signature: "npm:1.0.6" - checksum: 10/1e5a63aa82e8eb4e02d2977c6902983dee87b02e87ec5ec43ac3cb1e72da354003716570cd5190c0ad9e8a454c9d3237f4ad6e2f16d0902205a96a1c72b77ba5 - languageName: node - linkType: hard - "cookie-signature@npm:1.0.6": version: 1.0.6 resolution: "cookie-signature@npm:1.0.6" @@ -11710,20 +11571,6 @@ __metadata: languageName: node linkType: hard -"cookie-signature@npm:1.0.7": - version: 1.0.7 - resolution: "cookie-signature@npm:1.0.7" - checksum: 10/1a62808cd30d15fb43b70e19829b64d04b0802d8ef00275b57d152de4ae6a3208ca05c197b6668d104c4d9de389e53ccc2d3bc6bcaaffd9602461417d8c40710 - languageName: node - linkType: hard - -"cookie@npm:0.4.1": - version: 0.4.1 - resolution: "cookie@npm:0.4.1" - checksum: 10/0f2defd60ac93645ee31e82d11da695080435eb4fe5bed9b14d2fc4e0621a66f4c5c60f3eb05761df08a9d6279366e8646edfd1654f359d0b5afc25304fc4ddc - languageName: node - linkType: hard - "cookie@npm:0.6.0": version: 0.6.0 resolution: "cookie@npm:0.6.0" @@ -12769,14 +12616,7 @@ __metadata: languageName: node linkType: hard -"effect@npm:^3.2.5": - version: 3.2.5 - resolution: "effect@npm:3.2.5" - checksum: 10/7d5c92f102f87de13ce6c689981a98c78b0ef2cbe5ea370732c60a8049995d9ddda77943ae3049216db29eb9f307b09bccaaee05e40b04b77a6ecf1648544163 - languageName: node - linkType: hard - -"ejs@npm:^3.1.5, ejs@npm:^3.1.6, ejs@npm:^3.1.7, ejs@npm:^3.1.8, ejs@npm:^3.1.9": +"ejs@npm:^3.1.5, ejs@npm:^3.1.6, ejs@npm:^3.1.7, ejs@npm:^3.1.8": version: 3.1.9 resolution: "ejs@npm:3.1.9" dependencies: @@ -12794,7 +12634,7 @@ __metadata: languageName: node linkType: hard -"emittery@npm:^0.13.0, emittery@npm:^0.13.1": +"emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" checksum: 10/fbe214171d878b924eedf1757badf58a5dce071cd1fa7f620fa841a0901a80d6da47ff05929d53163105e621ce11a71b9d8acb1148ffe1745e045145f6e69521 @@ -14379,23 +14219,7 @@ __metadata: languageName: node linkType: hard -"express-session@npm:^1.17.3": - version: 1.18.0 - resolution: "express-session@npm:1.18.0" - dependencies: - cookie: "npm:0.6.0" - cookie-signature: "npm:1.0.7" - debug: "npm:2.6.9" - depd: "npm:~2.0.0" - on-headers: "npm:~1.0.2" - parseurl: "npm:~1.3.3" - safe-buffer: "npm:5.2.1" - uid-safe: "npm:~2.1.5" - checksum: 10/d0d8290615ef66fe01cd0514b0fcb4f0ed8399cf3dcaabac29f2e09e04636367d8a35948d4d8694edf655e0303f996a245ed6154e2fa44b70a107caa2638b0fb - languageName: node - linkType: hard - -"express@npm:^4.17.1, express@npm:^4.18.2": +"express@npm:^4.17.1": version: 4.19.2 resolution: "express@npm:4.19.2" dependencies: @@ -15096,17 +14920,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:~7.0.1": - version: 7.0.1 - resolution: "fs-extra@npm:7.0.1" - dependencies: - graceful-fs: "npm:^4.1.2" - jsonfile: "npm:^4.0.0" - universalify: "npm:^0.1.0" - checksum: 10/3fc6e56ba2f07c00d452163f27f21a7076b72ef7da8a50fef004336d59ef4c34deda11d10ecd73fd8fbcf20e4f575f52857293090b3c9f8741d4e0598be30fea - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -15520,7 +15333,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.4, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.4, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 @@ -16140,13 +15953,6 @@ __metadata: languageName: node linkType: hard -"import-lazy@npm:~4.0.0": - version: 4.0.0 - resolution: "import-lazy@npm:4.0.0" - checksum: 10/943309cc8eb01ada12700448c288b0384f77a1bc33c7e00fa4cb223c665f467a13ce9aaceb8d2e4cf586b07c1d2828040263dcc069873ce63cfc2ac6fd087971 - languageName: node - linkType: hard - "import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -17679,13 +17485,6 @@ __metadata: languageName: node linkType: hard -"jju@npm:~1.4.0": - version: 1.4.0 - resolution: "jju@npm:1.4.0" - checksum: 10/1067ff8ce02221faac5a842116ed0ec79a53312a111d0bf8342a80bd02c0a3fdf0b8449694a65947db0a3e8420e8b326dffb489c7dd5866efc380c0d1708a707 - languageName: node - linkType: hard - "jks-js@npm:1.1.0": version: 1.1.0 resolution: "jks-js@npm:1.1.0" @@ -17710,7 +17509,7 @@ __metadata: languageName: node linkType: hard -"joi@npm:^17.11.0, joi@npm:^17.2.1, joi@npm:^17.9.1": +"joi@npm:^17.11.0, joi@npm:^17.2.1": version: 17.12.2 resolution: "joi@npm:17.12.2" dependencies: @@ -20125,7 +19924,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.4, mkdirp@npm:~0.5.1": +"mkdirp@npm:^0.5.1, mkdirp@npm:~0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -20199,21 +19998,6 @@ __metadata: languageName: node linkType: hard -"multer@npm:1.4.5-lts.1": - version: 1.4.5-lts.1 - resolution: "multer@npm:1.4.5-lts.1" - dependencies: - append-field: "npm:^1.0.0" - busboy: "npm:^1.0.0" - concat-stream: "npm:^1.5.2" - mkdirp: "npm:^0.5.4" - object-assign: "npm:^4.1.1" - type-is: "npm:^1.6.4" - xtend: "npm:^4.0.0" - checksum: 10/957c09956f3b7f79d8586cac5e2a50e9a5c3011eb841667b5e4590c5f31d9464f5b46aecd399c83e183a15b88b019cccf0e4fa5620db40bf16b9e3af7fab3ac6 - languageName: node - linkType: hard - "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -21672,13 +21456,6 @@ __metadata: languageName: node linkType: hard -"pony-cause@npm:^2.1.4": - version: 2.1.10 - resolution: "pony-cause@npm:2.1.10" - checksum: 10/906563565030996d0c40ba79a584e2f298391931acc59c98510f9fd583d72cd9e9c58b0fb5a25bbae19daf16840f94cb9c1ee72c7ed5ef249ecba147cee40495 - languageName: node - linkType: hard - "posix-character-classes@npm:^0.1.0": version: 0.1.1 resolution: "posix-character-classes@npm:0.1.1" @@ -22083,7 +21860,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.11.0, qs@npm:^6.11.1, qs@npm:^6.11.2, qs@npm:^6.5.2": +"qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.5.2": version: 6.12.0 resolution: "qs@npm:6.12.0" dependencies: @@ -22152,13 +21929,6 @@ __metadata: languageName: node linkType: hard -"random-bytes@npm:~1.0.0": - version: 1.0.0 - resolution: "random-bytes@npm:1.0.0" - checksum: 10/09faa256394aa2ca9754aa57e92a27c452c3e97ffb266e98bebb517332e9df7168fea393159f88d884febce949ba8bec8ddb02f03342da6c6023ecc7b155e0ae - languageName: node - linkType: hard - "randomatic@npm:^3.0.0": version: 3.1.1 resolution: "randomatic@npm:3.1.1" @@ -23205,7 +22975,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.2, readable-stream@npm:^2.2.2, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.0.2, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -23671,7 +23441,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4, resolve@npm:~1.22.1": +"resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -23706,7 +23476,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.10.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A~1.22.1#optional!builtin": +"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.10.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.2#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -24136,7 +23906,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.5.4, semver@npm:~7.5.4": +"semver@npm:7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -25038,13 +24808,6 @@ __metadata: languageName: node linkType: hard -"string-argv@npm:~0.3.1": - version: 0.3.2 - resolution: "string-argv@npm:0.3.2" - checksum: 10/f9d3addf887026b4b5f997a271149e93bf71efc8692e7dc0816e8807f960b18bcb9787b45beedf0f97ff459575ee389af3f189d8b649834cac602f2e857e75af - languageName: node - linkType: hard - "string-convert@npm:^0.2.0": version: 0.2.1 resolution: "string-convert@npm:0.2.1" @@ -25385,7 +25148,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1, supports-color@npm:~8.1.1": +"supports-color@npm:^8.0.0, supports-color@npm:^8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -25916,6 +25679,13 @@ __metadata: languageName: node linkType: hard +"true-myth@npm:^7.3.0": + version: 7.3.0 + resolution: "true-myth@npm:7.3.0" + checksum: 10/d0c595a0dfa8fdd55dd47eae6d46d97a603b7ff3a22c1f098b2dfa5340681a533f3503e59f6e1ab3a5df7f672e889862290b5ed1a46fc4d82d7654b725d97886 + languageName: node + linkType: hard + "ts-api-utils@npm:^1.0.1": version: 1.3.0 resolution: "ts-api-utils@npm:1.3.0" @@ -25941,7 +25711,7 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^29.0.3, ts-jest@npm:^29.0.5, ts-jest@npm:^29.1.0": +"ts-jest@npm:^29.0.3, ts-jest@npm:^29.1.0": version: 29.1.2 resolution: "ts-jest@npm:29.1.2" dependencies: @@ -26149,13 +25919,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.0.0": - version: 4.14.0 - resolution: "type-fest@npm:4.14.0" - checksum: 10/fcf3b62fed194a3fc3d22bf287af3b1e1e93d4b5cb9723c093b694998d1588f27cc78dc4942ff4d319bb94ec60cb4afe5d1cd3d50ef144e47e327acbc34a5234 - languageName: node - linkType: hard - "type-graphql@npm:2.0.0-beta.3": version: 2.0.0-beta.3 resolution: "type-graphql@npm:2.0.0-beta.3" @@ -26198,7 +25961,7 @@ __metadata: languageName: node linkType: hard -"type-is@npm:^1.6.16, type-is@npm:^1.6.4, type-is@npm:~1.6.18": +"type-is@npm:^1.6.16, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" dependencies: @@ -26260,13 +26023,6 @@ __metadata: languageName: node linkType: hard -"typedarray@npm:^0.0.6": - version: 0.0.6 - resolution: "typedarray@npm:0.0.6" - checksum: 10/2cc1bcf7d8c1237f6a16c04efc06637b2c5f2d74e58e84665445cf87668b85a21ab18dd751fa49eee6ae024b70326635d7b79ad37b1c370ed2fec6aeeeb52714 - languageName: node - linkType: hard - "typedi@npm:^0.10.0": version: 0.10.0 resolution: "typedi@npm:0.10.0" @@ -26322,28 +26078,6 @@ __metadata: languageName: node linkType: hard -"uid-safe@npm:~2.1.5": - version: 2.1.5 - resolution: "uid-safe@npm:2.1.5" - dependencies: - random-bytes: "npm:~1.0.0" - checksum: 10/07536043da9a026f4a2bc397543d0ace7587449afa1d9d2c4fd3ce76af8a5263a678788bcc429dff499ef29d45843cd5ee9d05434450fcfc19cc661229f703d1 - languageName: node - linkType: hard - -"umzug@npm:^3.3.1": - version: 3.7.0 - resolution: "umzug@npm:3.7.0" - dependencies: - "@rushstack/ts-command-line": "npm:^4.12.2" - emittery: "npm:^0.13.0" - glob: "npm:^8.0.3" - pony-cause: "npm:^2.1.4" - type-fest: "npm:^4.0.0" - checksum: 10/2cd3ce78dfa473ae41bed7a0819710caef8fa5ed7a625a42b5f877610bfaa31bf2e99bb92d782d59d01db975f686bffdb60e4bcbf98b524434fc27eb43f56946 - languageName: node - linkType: hard - "unbox-primitive@npm:^1.0.2": version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" @@ -27720,23 +27454,6 @@ __metadata: languageName: node linkType: hard -"z-schema@npm:~5.0.2": - version: 5.0.5 - resolution: "z-schema@npm:5.0.5" - dependencies: - commander: "npm:^9.4.1" - lodash.get: "npm:^4.4.2" - lodash.isequal: "npm:^4.5.0" - validator: "npm:^13.7.0" - dependenciesMeta: - commander: - optional: true - bin: - z-schema: bin/z-schema - checksum: 10/8ac2fa445f5a00e790d1f91a48aeff0ccfc340f84626771853e03f4d97cdc2f5f798cdb2e38418f7815ffc3aac3952c45caabcf077bf4f83fedf0cdef43b885b - languageName: node - linkType: hard - "zen-observable-ts@npm:^1.2.5": version: 1.2.5 resolution: "zen-observable-ts@npm:1.2.5" From aaa64d7d020aacd70538dc272a8864f3c7a2a4e2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 07:09:36 +0000 Subject: [PATCH 067/153] Add unique constraint for db_num and marathon_id in db_funds_teams table --- .../migration.sql | 23 +++++++++++++++++++ packages/server/prisma/schema.prisma | 22 +++++++++++------- 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 packages/server/prisma/migrations/20240529070925_unique_dbnum_on_marathon/migration.sql diff --git a/packages/server/prisma/migrations/20240529070925_unique_dbnum_on_marathon/migration.sql b/packages/server/prisma/migrations/20240529070925_unique_dbnum_on_marathon/migration.sql new file mode 100644 index 00000000..5ccaedaa --- /dev/null +++ b/packages/server/prisma/migrations/20240529070925_unique_dbnum_on_marathon/migration.sql @@ -0,0 +1,23 @@ +/* + Warnings: + + - A unique constraint covering the columns `[db_num,marathon_id]` on the table `db_funds_teams` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropForeignKey +ALTER TABLE "db_funds_team_entries" DROP CONSTRAINT "db_funds_team_entries_team_db_num_fkey"; + +-- DropIndex +DROP INDEX "db_funds_teams_db_num_key"; + +-- AlterTable +ALTER TABLE "db_funds_teams" ADD COLUMN "marathon_id" INTEGER; + +-- CreateIndex +CREATE UNIQUE INDEX "db_funds_teams_db_num_marathon_id_key" ON "db_funds_teams"("db_num", "marathon_id"); + +-- AddForeignKey +ALTER TABLE "db_funds_teams" ADD CONSTRAINT "db_funds_teams_marathon_id_fkey" FOREIGN KEY ("marathon_id") REFERENCES "marathons"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "db_funds_team_entries" ADD CONSTRAINT "db_funds_team_entries_team_db_num_fkey" FOREIGN KEY ("team_db_num") REFERENCES "db_funds_teams"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 52d56b8c..531bac80 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -351,6 +351,7 @@ model Marathon { hours MarathonHour[] teams Team[] teamsWithTotalPoints TeamsWithTotalPoints[] + dbFundsTeams DBFundsTeam[] @@index([uuid], map: "marathons_uuid") @@map("marathons") @@ -406,7 +407,7 @@ model DBFundsTeam { // Unrelated to the 'id' field in the DBFunds API id Int @id @default(autoincrement()) // The team's DbNum from the DBFunds API - dbNum Int @unique @map("db_num") + dbNum Int @map("db_num") // The team's name from the DBFunds API name String // The team's total fundraising amount from the DBFunds API @@ -416,27 +417,32 @@ model DBFundsTeam { // All fundraising entries for the team fundraisingEntries DBFundsFundraisingEntry[] + // The marathon the team is associated with + marathon Marathon? @relation(fields: [marathonId], references: [id]) + marathonId Int? @map("marathon_id") + // The corresponding team in our database team Team? + @@unique([dbNum, marathonId], map: "db_funds_teams_db_num_marathon_id_key") @@map("db_funds_teams") } // This table is kept in sync with the DBFunds API and should not be modified model DBFundsFundraisingEntry { // Unrelated to the 'id' field in the DBFunds API - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) // The amount of the entry - amount Decimal + amount Decimal // Who made the donation - donatedBy String @map("donated_by") + donatedBy String @map("donated_by") // Who the donation was made for - donatedTo String @map("donated_to") + donatedTo String @map("donated_to") // The date of the donation - date DateTime + date DateTime // The team's DbNum from the DBFunds API - teamDbNum Int @map("team_db_num") - team DBFundsTeam @relation(fields: [teamDbNum], references: [dbNum]) + dbFundsTeamId Int @map("team_db_num") + dbFundsTeam DBFundsTeam @relation(fields: [dbFundsTeamId], references: [id]) // The corresponding fundraising entry in our database fundraisingEntry FundraisingEntry? From f6b286839fd858ae9201fbd0857fcbba64201784 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 29 May 2024 07:09:58 +0000 Subject: [PATCH 068/153] Start on new error handling --- packages/server/src/lib/error/error.ts | 38 ++++++++++++ packages/server/src/lib/error/http.ts | 21 +++++++ packages/server/src/lib/error/prisma.ts | 82 +++++++++++++++++++++++++ packages/server/src/lib/error/result.ts | 15 +++++ packages/server/src/lib/error/zod.ts | 17 +++++ 5 files changed, 173 insertions(+) create mode 100644 packages/server/src/lib/error/error.ts create mode 100644 packages/server/src/lib/error/http.ts create mode 100644 packages/server/src/lib/error/prisma.ts create mode 100644 packages/server/src/lib/error/result.ts create mode 100644 packages/server/src/lib/error/zod.ts diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts new file mode 100644 index 00000000..59dc2efb --- /dev/null +++ b/packages/server/src/lib/error/error.ts @@ -0,0 +1,38 @@ +export abstract class ConcreteError { + abstract get message(): string; + abstract get expose(): boolean; + get stack(): string | undefined { + return undefined; + } +} + +export class JsError extends ConcreteError { + readonly error: Error; + + constructor(error: Error) { + super(); + this.error = error; + } + + get message(): string { + return this.error.message; + } + + get expose(): boolean { + return false; + } + + get stack(): string | undefined { + return this.error.stack; + } +} + +export class UnknownError extends ConcreteError { + get message(): string { + return "Unknown error"; + } + + get expose(): boolean { + return false; + } +} diff --git a/packages/server/src/lib/error/http.ts b/packages/server/src/lib/error/http.ts new file mode 100644 index 00000000..26e632c6 --- /dev/null +++ b/packages/server/src/lib/error/http.ts @@ -0,0 +1,21 @@ +import type { StatusCodes } from "http-status-codes"; +import { getReasonPhrase } from "http-status-codes"; + +import { ConcreteError } from "./error.js"; + +export class HttpError extends ConcreteError { + readonly code: StatusCodes; + + constructor(code: StatusCodes | Response) { + super(); + this.code = code instanceof Response ? code.status : code; + } + + get message(): string { + return getReasonPhrase(this.code); + } + + get expose(): boolean { + return true; + } +} diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts new file mode 100644 index 00000000..30b83d90 --- /dev/null +++ b/packages/server/src/lib/error/prisma.ts @@ -0,0 +1,82 @@ +import type { + PrismaClientInitializationError, + PrismaClientKnownRequestError, + PrismaClientRustPanicError, + PrismaClientUnknownRequestError, + PrismaClientValidationError, +} from "@prisma/client/runtime/library"; + +import { ConcreteError } from "./error.js"; + +type RawPrismaError = + | PrismaClientKnownRequestError + | PrismaClientUnknownRequestError + | PrismaClientRustPanicError + | PrismaClientInitializationError + | PrismaClientValidationError; + +export abstract class PrismaError extends ConcreteError { + readonly error: RawPrismaError; + + constructor(error: RawPrismaError) { + super(); + this.error = error; + } + + get message(): string { + return this.error.message; + } + + get stack(): string | undefined { + return this.error.stack; + } + + get expose(): boolean { + return false; + } +} + +export class PrismaKnownRequestError extends PrismaError { + readonly error: PrismaClientKnownRequestError; + + constructor(error: PrismaClientKnownRequestError) { + super(error); + this.error = error; + } +} + +export class PrismaUnknownRequestError extends PrismaError { + readonly error: PrismaClientUnknownRequestError; + + constructor(error: PrismaClientUnknownRequestError) { + super(error); + this.error = error; + } +} + +export class PrismaRustPanicError extends PrismaError { + readonly error: PrismaClientRustPanicError; + + constructor(error: PrismaClientRustPanicError) { + super(error); + this.error = error; + } +} + +export class PrismaInitializationError extends PrismaError { + readonly error: PrismaClientInitializationError; + + constructor(error: PrismaClientInitializationError) { + super(error); + this.error = error; + } +} + +export class PrismaValidationError extends PrismaError { + readonly error: PrismaClientValidationError; + + constructor(error: PrismaClientValidationError) { + super(error); + this.error = error; + } +} diff --git a/packages/server/src/lib/error/result.ts b/packages/server/src/lib/error/result.ts new file mode 100644 index 00000000..725d70c9 --- /dev/null +++ b/packages/server/src/lib/error/result.ts @@ -0,0 +1,15 @@ +import type { Result } from "true-myth"; + +import type { JsError, UnknownError } from "./error.js"; +import type { HttpError } from "./http.js"; +import type { PrismaError } from "./prisma.js"; +import type { ZodError } from "./zod.js"; + +export type ConcreteErrorTypes = + | UnknownError + | JsError + | HttpError + | PrismaError + | ZodError; + +export type ConcreteResult = Result; diff --git a/packages/server/src/lib/error/zod.ts b/packages/server/src/lib/error/zod.ts new file mode 100644 index 00000000..354148b9 --- /dev/null +++ b/packages/server/src/lib/error/zod.ts @@ -0,0 +1,17 @@ +import type { ZodError as RawZodError } from "zod"; + +import { ConcreteError } from "./error.js"; + +export class ZodError extends ConcreteError { + readonly error: RawZodError; + constructor(error: RawZodError) { + super(); + this.error = error; + } + get message() { + return this.error.message; + } + get expose() { + return false; + } +} From b986640af169491825194954e9d10b323fcc7c58 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:14:38 +0000 Subject: [PATCH 069/153] Refactor error classes and result types --- packages/server/src/lib/error/error.ts | 12 +++++++++++- packages/server/src/lib/error/http.ts | 9 ++++----- packages/server/src/lib/error/result.ts | 18 +++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index 59dc2efb..426cd89c 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -28,8 +28,18 @@ export class JsError extends ConcreteError { } export class UnknownError extends ConcreteError { + readonly #message: string = "Unknown error"; + + // We use a rest parameter here to detect when undefined is passed. If we just allowed an optional parameter, we wouldn't be able to distinguish between `new UnknownError()` and `new UnknownError(undefined)`. + constructor(...message: unknown[]) { + super(); + if (message.length > 0) { + this.#message = String(message[0]); + } + } + get message(): string { - return "Unknown error"; + return this.#message; } get expose(): boolean { diff --git a/packages/server/src/lib/error/http.ts b/packages/server/src/lib/error/http.ts index 26e632c6..b0f3db07 100644 --- a/packages/server/src/lib/error/http.ts +++ b/packages/server/src/lib/error/http.ts @@ -3,12 +3,11 @@ import { getReasonPhrase } from "http-status-codes"; import { ConcreteError } from "./error.js"; -export class HttpError extends ConcreteError { - readonly code: StatusCodes; - - constructor(code: StatusCodes | Response) { +export class HttpError< + Code extends StatusCodes = StatusCodes, +> extends ConcreteError { + constructor(readonly code: Code) { super(); - this.code = code instanceof Response ? code.status : code; } get message(): string { diff --git a/packages/server/src/lib/error/result.ts b/packages/server/src/lib/error/result.ts index 725d70c9..b35f513c 100644 --- a/packages/server/src/lib/error/result.ts +++ b/packages/server/src/lib/error/result.ts @@ -1,6 +1,7 @@ -import type { Result } from "true-myth"; +import { Result } from "true-myth"; -import type { JsError, UnknownError } from "./error.js"; +import type { ConcreteError } from "./error.js"; +import { JsError, UnknownError } from "./error.js"; import type { HttpError } from "./http.js"; import type { PrismaError } from "./prisma.js"; import type { ZodError } from "./zod.js"; @@ -12,4 +13,15 @@ export type ConcreteErrorTypes = | PrismaError | ZodError; -export type ConcreteResult = Result; +export type ConcreteResult = Result; + +export type JsResult = ConcreteResult< + T, + E | JsError | UnknownError +>; + +export function resultFromJsError(error: unknown): JsResult { + return Result.err( + error instanceof Error ? new JsError(error) : new UnknownError(error) + ); +} From 179c5865b6c4f3e05ecfa079f60b502d705a2105 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:14:47 +0000 Subject: [PATCH 070/153] Add DBFundsFundraisingProvider implementation --- .../src/lib/fundraising/DbFundsProvider.ts | 182 ++++++++++++++++++ .../lib/fundraising/FundraisingProvider.ts | 32 +++ 2 files changed, 214 insertions(+) create mode 100644 packages/server/src/lib/fundraising/DbFundsProvider.ts create mode 100644 packages/server/src/lib/fundraising/FundraisingProvider.ts diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts new file mode 100644 index 00000000..715b6ff7 --- /dev/null +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -0,0 +1,182 @@ +import type { MarathonYearString } from "@ukdanceblue/common"; +import { DateTime } from "luxon"; +import { Result } from "true-myth"; +import { Inject, Service } from "typedi"; +import { z } from "zod"; + +import { + dbFundsApiKeyToken, + dbFundsApiOriginToken, +} from "../../environment.js"; +import { JsError, UnknownError } from "../error/error.js"; +import { HttpError } from "../error/http.js"; +import { ConcreteResult, resultFromJsError } from "../error/result.js"; +import { ZodError } from "../error/zod.js"; + +import type { + FundraisingEntry, + FundraisingProvider, + FundraisingTeam, +} from "./FundraisingProvider.js"; + +export interface DbFundsFundraisingTeam extends FundraisingTeam { + dbNum: number; +} + +const dbFundsFundraisingTeamSchema = z.object({ + dbNum: z.number().int().nonnegative().describe("The team's dbNum"), + name: z.string().describe("The name of the team"), + total: z + .number() + .describe( + "The amount donated in dollars, with two decimal places for cents" + ) + .nonnegative() + .multipleOf(0.01, "Must be a whole number of cents"), +}); + +export interface DbFundsFundraisingEntry extends FundraisingEntry {} + +const dbFundsFundraisingEntrySchema = z.object({ + dbNum: z + .number() + .describe("The dbNum of the team to which these entries belong") + .int() + .nonnegative(), + name: z + .string() + .describe("The name of the team to which these entries belong"), + entries: z.array( + z.object({ + donatedBy: z.string().describe("The name of the person who donated"), + donatedTo: z + .string() + .describe("The name of the person or team who received the donation") + .transform((v) => (v === "N/A" ? null : v)) + .nullable(), + donatedOn: z + .string() + .describe("The date and time the donation was made, in Eastern time") + .datetime(), + // NOTE: Currently the API sends the amount as a number of cents (i.e. it sends 100.00 for $1.00) even though the total is + // in dollars (i.e. it sends 1.00 for $1.00). This is a bit inconsistent, but it's not a big deal. We can just convert the + // amount to dollars when we use it and this has already taken long enough to get going that I don't want to spend time + // waiting for DBFunds to fix it. + amount: z + .number() + .describe("The amount donated in cents") + .nonnegative() + .int(), + }) + ), +}); + +function teamTotalPath(year: number | string): string { + return `/api/report/teamtotals/${year}`; +} + +function teamEntriesPath( + dbNum: number | string, + year: number | string +): string { + return `/api/report/teamentries/${dbNum}/${year}`; +} + +@Service() +export class DBFundsFundraisingProvider implements FundraisingProvider { + constructor( + @Inject(dbFundsApiOriginToken) + private readonly dbFundsApiOrigin: string, + @Inject(dbFundsApiKeyToken) + private readonly dbFundsApiKey: string + ) {} + + private async fetchJson( + path: string | URL + ): Promise> { + let response: Response; + try { + const url = new URL(path, this.dbFundsApiOrigin); + response = await fetch(url, { + headers: { + "X-AuthToken": this.dbFundsApiKey, + }, + }); + } catch (error) { + return resultFromJsError(error); + } + + if (!response.ok) { + return Result.err(new HttpError(response.status)); + } + + return Result.ok(await response.json()); + } + + async getTeams( + marathonYear: MarathonYearString + ): Promise< + ConcreteResult< + DbFundsFundraisingTeam[], + HttpError | JsError | UnknownError | ZodError + > + > { + const calendarYear = `20${marathonYear.substring(2)}`; + const path = teamTotalPath(calendarYear); + const result = await this.fetchJson(path); + if (result.isErr) { + return result.cast(); + } + + const teams = dbFundsFundraisingTeamSchema.array().safeParse(result.value); + if (teams.success) { + return Result.ok( + teams.data.map((team) => ({ + name: team.name, + dbNum: team.dbNum, + total: team.total, + })) + ); + } else { + return Result.err(new ZodError(teams.error)); + } + } + async getTeamEntries( + marathonYear: MarathonYearString, + dbNum: number + ): Promise< + ConcreteResult< + DbFundsFundraisingEntry[], + HttpError | JsError | UnknownError | ZodError + > + > { + const calendarYear = `20${marathonYear.substring(2)}`; + const path = teamEntriesPath(dbNum, calendarYear); + + const result = await this.fetchJson(path); + if (result.isErr) { + return result.cast(); + } + + const entries = dbFundsFundraisingEntrySchema + .array() + .safeParse(result.value); + if (entries.success) { + return Result.ok( + entries.data.flatMap((team) => + team.entries.map((entry) => ({ + donatedBy: entry.donatedBy, + donatedTo: entry.donatedTo, + // donatedOn is in Eastern time + donatedOn: DateTime.fromISO(entry.donatedOn, { + zone: "America/New_York", + }), + amount: entry.amount, + })) + ) + ); + } else { + return Result.err(new ZodError(entries.error)); + } + } +} diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts new file mode 100644 index 00000000..ba65233f --- /dev/null +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -0,0 +1,32 @@ +import type { MarathonYearString } from "@ukdanceblue/common"; +import type { DateTime } from "luxon"; + +import type { JsError, UnknownError } from "../error/error.js"; +import type { HttpError } from "../error/http.js"; +import type { ConcreteResult } from "../error/result.js"; + +export interface FundraisingTeam { + name: string; + total: number; +} + +export interface FundraisingEntry { + donatedBy: string; + donatedTo?: string | null | undefined; + donatedOn: DateTime; + amount: number; +} + +export interface FundraisingProvider { + getTeams( + marathonYear: MarathonYearString + ): Promise< + ConcreteResult + >; + getTeamEntries( + marathonYear: MarathonYearString, + identifier: unknown + ): Promise< + ConcreteResult + >; +} From 3ab18952e1733aa7e8c9a1859a56d1b859c59aa4 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:15:01 +0000 Subject: [PATCH 071/153] Add zod package for runtime type validation --- packages/server/package.json | 3 ++- yarn.lock | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/server/package.json b/packages/server/package.json index db04247b..57afc6e0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -68,7 +68,8 @@ "typescript": "^5.4.3", "utility-types": "^3.10.0", "validator": "^13.9.0", - "winston": "^3.8.2" + "winston": "^3.8.2", + "zod": "^3.23.8" }, "devDependencies": { "@types/koa": "^2.13.6", diff --git a/yarn.lock b/yarn.lock index 47a5c3ee..97b2902a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8639,6 +8639,7 @@ __metadata: validator: "npm:^13.9.0" vitest: "npm:^1.4.0" winston: "npm:^3.8.2" + zod: "npm:^3.23.8" languageName: unknown linkType: soft @@ -27477,6 +27478,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.23.8": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 10/846fd73e1af0def79c19d510ea9e4a795544a67d5b34b7e1c4d0425bf6bfd1c719446d94cdfa1721c1987d891321d61f779e8236fde517dc0e524aa851a6eff1 + languageName: node + linkType: hard + "zustand@npm:^4.1.5": version: 4.5.2 resolution: "zustand@npm:4.5.2" From a06310f5bfe0136dacc24bdf218f90df9bb50f01 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:15:27 +0000 Subject: [PATCH 072/153] Add DBFunds config to env --- packages/server/src/environment.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index 26eff440..b0442084 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -3,7 +3,7 @@ import path, { isAbsolute } from "path"; import dotenv from "dotenv"; import { Expo } from "expo-server-sdk"; -import { Container } from "typedi"; +import { Container, Token } from "typedi"; import type { SyslogLevels } from "./lib/logging/standardLogging.js"; @@ -101,6 +101,20 @@ export const expoAccessToken = EXPO_ACCESS_TOKEN; Container.set(Expo, new Expo({ accessToken: expoAccessToken })); +// DBFunds +const { DBFUNDS_API_KEY, DBFUNDS_API_ORIGIN } = process.env; +if (!DBFUNDS_API_KEY) { + throw new Error("DBFUNDS_API_KEY is not set"); +} +if (!DBFUNDS_API_ORIGIN) { + throw new Error("DBFUNDS_API_ORIGIN is not set"); +} +export const dbFundsApiKeyToken = new Token("DBFUNDS_API_KEY"); +export const dbFundsApiOriginToken = new Token("DBFUNDS_API_ORIGIN"); + +Container.set(dbFundsApiKeyToken, DBFUNDS_API_KEY); +Container.set(dbFundsApiOriginToken, DBFUNDS_API_ORIGIN); + // File upload settings const { MAX_FILE_SIZE, SERVE_PATH, UPLOAD_PATH, SERVE_ORIGIN } = process.env; if (!MAX_FILE_SIZE) { From 8a62b17f525d60b0e9fe518f650aa3f3f7c784a6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:48:17 +0000 Subject: [PATCH 073/153] Update foreign key constraints for DBFunds team entries --- .../20240530184804_dbfunds_tweaks/migration.sql | 8 ++++++++ packages/server/prisma/schema.prisma | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 packages/server/prisma/migrations/20240530184804_dbfunds_tweaks/migration.sql diff --git a/packages/server/prisma/migrations/20240530184804_dbfunds_tweaks/migration.sql b/packages/server/prisma/migrations/20240530184804_dbfunds_tweaks/migration.sql new file mode 100644 index 00000000..fa583e43 --- /dev/null +++ b/packages/server/prisma/migrations/20240530184804_dbfunds_tweaks/migration.sql @@ -0,0 +1,8 @@ +-- DropForeignKey +ALTER TABLE "db_funds_team_entries" DROP CONSTRAINT "db_funds_team_entries_team_db_num_fkey"; + +-- AlterTable +ALTER TABLE "db_funds_team_entries" ALTER COLUMN "donated_to" DROP NOT NULL; + +-- AddForeignKey +ALTER TABLE "db_funds_team_entries" ADD CONSTRAINT "db_funds_team_entries_team_db_num_fkey" FOREIGN KEY ("team_db_num") REFERENCES "db_funds_teams"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 531bac80..dc3f5850 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -437,12 +437,12 @@ model DBFundsFundraisingEntry { // Who made the donation donatedBy String @map("donated_by") // Who the donation was made for - donatedTo String @map("donated_to") + donatedTo String? @map("donated_to") // The date of the donation date DateTime // The team's DbNum from the DBFunds API dbFundsTeamId Int @map("team_db_num") - dbFundsTeam DBFundsTeam @relation(fields: [dbFundsTeamId], references: [id]) + dbFundsTeam DBFundsTeam @relation(fields: [dbFundsTeamId], references: [id], onDelete: Cascade) // The corresponding fundraising entry in our database fundraisingEntry FundraisingEntry? @@ -458,7 +458,7 @@ model FundraisingEntry { updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) totalAmount Decimal @map("total_amount") - dbFundsEntry DBFundsFundraisingEntry? @relation(references: [donatedBy, date], fields: [dbFundsEntryDonatedBy, dbFundsEntryDate]) + dbFundsEntry DBFundsFundraisingEntry? @relation(references: [donatedBy, date], fields: [dbFundsEntryDonatedBy, dbFundsEntryDate], onDelete: SetNull) dbFundsEntryDonatedBy String? @map("db_funds_entry_donated_by") dbFundsEntryDate DateTime? @map("db_funds_entry_date") From 742aff4a1ad9ad180f87c0a548c90667fdba1a83 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:48:25 +0000 Subject: [PATCH 074/153] Refactor error classes and add NotFoundError class --- packages/server/src/lib/error/direct.ts | 50 +++++++++++++++++++++++++ packages/server/src/lib/error/error.ts | 9 +++++ packages/server/src/lib/error/prisma.ts | 30 ++++++++++++++- packages/server/src/lib/error/result.ts | 11 +----- 4 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 packages/server/src/lib/error/direct.ts diff --git a/packages/server/src/lib/error/direct.ts b/packages/server/src/lib/error/direct.ts new file mode 100644 index 00000000..a81180b7 --- /dev/null +++ b/packages/server/src/lib/error/direct.ts @@ -0,0 +1,50 @@ +import { Maybe } from "true-myth"; + +import { ConcreteError } from "./error.js"; + +export class NotFoundError extends ConcreteError { + readonly #what: Maybe; + readonly #where: Maybe; + readonly #why: Maybe; + readonly #sensitive: boolean; + + constructor({ + what, + where, + why, + sensitive = true, + }: { + what?: string; + where?: string; + why?: string; + sensitive?: boolean; + }) { + super(); + this.#what = Maybe.of(what); + this.#where = Maybe.of(where); + this.#why = Maybe.of(why); + this.#sensitive = sensitive; + } + + get message(): string { + return this.#what.mapOr("Not found", (what) => `Not found: ${what}`); + } + + get detailedMessage(): string { + return `Not found: ${this.#what.unwrapOr("unknown")}${this.#where.match({ + Just: (where) => ` at ${where}`, + Nothing: () => "", + })}${this.#why.match({ + Just: (why) => ` because ${why}`, + Nothing: () => "", + })}`; + } + + get expose(): boolean { + return !this.#sensitive; + } + + get stack(): string | undefined { + return undefined; + } +} diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index 426cd89c..4625ec06 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -1,5 +1,8 @@ export abstract class ConcreteError { abstract get message(): string; + get detailedMessage(): string { + return this.message; + } abstract get expose(): boolean; get stack(): string | undefined { return undefined; @@ -46,3 +49,9 @@ export class UnknownError extends ConcreteError { return false; } } + +export type BasicError = JsError | UnknownError; + +export function asBasicError(error: unknown): BasicError { + return error instanceof Error ? new JsError(error) : new UnknownError(error); +} diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts index 30b83d90..f9f041f2 100644 --- a/packages/server/src/lib/error/prisma.ts +++ b/packages/server/src/lib/error/prisma.ts @@ -1,10 +1,11 @@ -import type { +import { PrismaClientInitializationError, PrismaClientKnownRequestError, PrismaClientRustPanicError, PrismaClientUnknownRequestError, PrismaClientValidationError, } from "@prisma/client/runtime/library"; +import { Maybe } from "true-myth"; import { ConcreteError } from "./error.js"; @@ -80,3 +81,30 @@ export class PrismaValidationError extends PrismaError { this.error = error; } } + +export function toPrismaError( + error: unknown +): Maybe< + | PrismaInitializationError + | PrismaKnownRequestError + | PrismaRustPanicError + | PrismaUnknownRequestError + | PrismaValidationError +> { + if (error instanceof PrismaClientInitializationError) { + return Maybe.of(new PrismaInitializationError(error)); + } + if (error instanceof PrismaClientKnownRequestError) { + return Maybe.of(new PrismaKnownRequestError(error)); + } + if (error instanceof PrismaClientRustPanicError) { + return Maybe.of(new PrismaRustPanicError(error)); + } + if (error instanceof PrismaClientUnknownRequestError) { + return Maybe.of(new PrismaUnknownRequestError(error)); + } + if (error instanceof PrismaClientValidationError) { + return Maybe.of(new PrismaValidationError(error)); + } + return Maybe.nothing(); +} diff --git a/packages/server/src/lib/error/result.ts b/packages/server/src/lib/error/result.ts index b35f513c..fa6bc2d5 100644 --- a/packages/server/src/lib/error/result.ts +++ b/packages/server/src/lib/error/result.ts @@ -1,7 +1,6 @@ -import { Result } from "true-myth"; +import type { Result } from "true-myth"; -import type { ConcreteError } from "./error.js"; -import { JsError, UnknownError } from "./error.js"; +import type { ConcreteError, JsError, UnknownError } from "./error.js"; import type { HttpError } from "./http.js"; import type { PrismaError } from "./prisma.js"; import type { ZodError } from "./zod.js"; @@ -19,9 +18,3 @@ export type JsResult = ConcreteResult< T, E | JsError | UnknownError >; - -export function resultFromJsError(error: unknown): JsResult { - return Result.err( - error instanceof Error ? new JsError(error) : new UnknownError(error) - ); -} From a43149ce528c41d49a95b98938334601376e44de Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:48:31 +0000 Subject: [PATCH 075/153] Refactor DBFundsFundraisingProvider and add identifier to FundraisingTeam --- .../src/lib/fundraising/DbFundsProvider.ts | 24 +++++++------------ .../lib/fundraising/FundraisingProvider.ts | 13 ++++++---- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 715b6ff7..a737dfbc 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -1,6 +1,6 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import { DateTime } from "luxon"; -import { Result } from "true-myth"; +import { Maybe, Result } from "true-myth"; import { Inject, Service } from "typedi"; import { z } from "zod"; @@ -8,9 +8,9 @@ import { dbFundsApiKeyToken, dbFundsApiOriginToken, } from "../../environment.js"; -import { JsError, UnknownError } from "../error/error.js"; +import { JsError, UnknownError, asBasicError } from "../error/error.js"; import { HttpError } from "../error/http.js"; -import { ConcreteResult, resultFromJsError } from "../error/result.js"; +import { ConcreteResult } from "../error/result.js"; import { ZodError } from "../error/zod.js"; import type { @@ -19,10 +19,6 @@ import type { FundraisingTeam, } from "./FundraisingProvider.js"; -export interface DbFundsFundraisingTeam extends FundraisingTeam { - dbNum: number; -} - const dbFundsFundraisingTeamSchema = z.object({ dbNum: z.number().int().nonnegative().describe("The team's dbNum"), name: z.string().describe("The name of the team"), @@ -35,8 +31,6 @@ const dbFundsFundraisingTeamSchema = z.object({ .multipleOf(0.01, "Must be a whole number of cents"), }); -export interface DbFundsFundraisingEntry extends FundraisingEntry {} - const dbFundsFundraisingEntrySchema = z.object({ dbNum: z .number() @@ -83,7 +77,7 @@ function teamEntriesPath( } @Service() -export class DBFundsFundraisingProvider implements FundraisingProvider { +export class DBFundsFundraisingProvider implements FundraisingProvider { constructor( @Inject(dbFundsApiOriginToken) private readonly dbFundsApiOrigin: string, @@ -103,7 +97,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { }, }); } catch (error) { - return resultFromJsError(error); + return Result.err(asBasicError(error)); } if (!response.ok) { @@ -117,7 +111,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { marathonYear: MarathonYearString ): Promise< ConcreteResult< - DbFundsFundraisingTeam[], + FundraisingTeam[], HttpError | JsError | UnknownError | ZodError > > { @@ -133,7 +127,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { return Result.ok( teams.data.map((team) => ({ name: team.name, - dbNum: team.dbNum, + identifier: team.dbNum, total: team.total, })) ); @@ -146,7 +140,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { dbNum: number ): Promise< ConcreteResult< - DbFundsFundraisingEntry[], + FundraisingEntry[], HttpError | JsError | UnknownError | ZodError > > { @@ -166,7 +160,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { entries.data.flatMap((team) => team.entries.map((entry) => ({ donatedBy: entry.donatedBy, - donatedTo: entry.donatedTo, + donatedTo: Maybe.of(entry.donatedTo), // donatedOn is in Eastern time donatedOn: DateTime.fromISO(entry.donatedOn, { zone: "America/New_York", diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index ba65233f..2bd3acba 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -1,27 +1,32 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; +import type { Maybe } from "true-myth"; import type { JsError, UnknownError } from "../error/error.js"; import type { HttpError } from "../error/http.js"; import type { ConcreteResult } from "../error/result.js"; -export interface FundraisingTeam { +export interface FundraisingTeam { name: string; + identifier: IDType; total: number; } export interface FundraisingEntry { donatedBy: string; - donatedTo?: string | null | undefined; + donatedTo: Maybe; donatedOn: DateTime; amount: number; } -export interface FundraisingProvider { +export interface FundraisingProvider { getTeams( marathonYear: MarathonYearString ): Promise< - ConcreteResult + ConcreteResult< + FundraisingTeam[], + HttpError | JsError | UnknownError + > >; getTeamEntries( marathonYear: MarathonYearString, From f978e3a8818397d09ff6bd5a9b8a254177c2762c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:48:46 +0000 Subject: [PATCH 076/153] Start DBFunds repository --- .../repositories/dbfunds/DBFundsRepository.ts | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 packages/server/src/repositories/dbfunds/DBFundsRepository.ts diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts new file mode 100644 index 00000000..eac00459 --- /dev/null +++ b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts @@ -0,0 +1,82 @@ +import type { PrismaClient } from "@prisma/client"; +import type { DateTime } from "luxon"; +import { Maybe, Result } from "true-myth"; +import { Service } from "typedi"; + +import { NotFoundError } from "../../lib/error/direct.js"; +import { asBasicError } from "../../lib/error/error.js"; +import { toPrismaError, type PrismaError } from "../../lib/error/prisma.js"; +import { type JsResult } from "../../lib/error/result.js"; +import type { + MarathonRepository, + UniqueMarathonParam, +} from "../marathon/MarathonRepository.js"; + +@Service() +export class DBFundsRepository { + constructor( + private readonly prisma: PrismaClient, + private readonly marathonRepository: MarathonRepository + ) {} + + async overwriteTeamForFiscalYear( + dbNum: number, + total: number, + marathonParam: UniqueMarathonParam, + entries: { + donatedBy: string; + donatedTo: Maybe; + donatedOn: DateTime; + amount: number; + }[] + ): Promise> { + try { + const marathon = + await this.marathonRepository.findMarathonByUnique(marathonParam); + if (!marathon) { + return Result.err(new NotFoundError({ what: "Marathon" })); + } + await this.prisma.dBFundsTeam.upsert({ + where: { + dbNum_marathonId: { + dbNum, + marathonId: marathon.id, + }, + }, + create: { + dbNum, + totalAmount: total, + marathon: { + connect: { id: marathon.id }, + }, + entries: { + create: entries.map((entry) => ({ + donatedBy: entry.donatedBy, + donatedTo: entry.donatedTo.unwrapOr(null), + donatedOn: entry.donatedOn.toJSDate(), + amount: entry.amount, + })), + }, + }, + update: { + totalAmount: total, + fundraisingEntries: { + deleteMany: {}, + createMany: { + data: entries.map((entry) => ({ + donatedBy: entry.donatedBy, + donatedTo: entry.donatedTo.unwrapOr(null), + date: entry.donatedOn.toJSDate(), + amount: entry.amount, + })), + }, + }, + }, + }); + } catch (error) { + return Result.err( + toPrismaError(error).unwrapOrElse(() => asBasicError(error)) + ); + } + } +} From d1a4b65b205e49e636285aa846271af119a446f8 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 30 May 2024 18:56:09 +0000 Subject: [PATCH 077/153] Refactor DBFundsFundraisingProvider and update FundraisingTeam interface --- .../src/lib/fundraising/DbFundsProvider.ts | 14 +++--- .../lib/fundraising/FundraisingProvider.ts | 1 + .../repositories/dbfunds/DBFundsRepository.ts | 44 +++++++++++-------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index a737dfbc..7076d2c5 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -20,9 +20,10 @@ import type { } from "./FundraisingProvider.js"; const dbFundsFundraisingTeamSchema = z.object({ - dbNum: z.number().int().nonnegative().describe("The team's dbNum"), - name: z.string().describe("The name of the team"), - total: z + DbNum: z.number().int().nonnegative().describe("The team's dbNum"), + Team: z.string().describe("The name of the team"), + Active: z.boolean().describe("Whether the team is active"), + Total: z .number() .describe( "The amount donated in dollars, with two decimal places for cents" @@ -126,9 +127,10 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { if (teams.success) { return Result.ok( teams.data.map((team) => ({ - name: team.name, - identifier: team.dbNum, - total: team.total, + name: team.Team, + active: team.Active, + identifier: team.DbNum, + total: team.Total, })) ); } else { diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index 2bd3acba..5de0f422 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -8,6 +8,7 @@ import type { ConcreteResult } from "../error/result.js"; export interface FundraisingTeam { name: string; + active: boolean; identifier: IDType; total: number; } diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts index eac00459..c32ae762 100644 --- a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts +++ b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts @@ -5,7 +5,7 @@ import { Service } from "typedi"; import { NotFoundError } from "../../lib/error/direct.js"; import { asBasicError } from "../../lib/error/error.js"; -import { toPrismaError, type PrismaError } from "../../lib/error/prisma.js"; +import { PrismaError, toPrismaError } from "../../lib/error/prisma.js"; import { type JsResult } from "../../lib/error/result.js"; import type { MarathonRepository, @@ -20,8 +20,12 @@ export class DBFundsRepository { ) {} async overwriteTeamForFiscalYear( - dbNum: number, - total: number, + team: { + total: number; + dbNum: number; + active: boolean; + name: string; + }, marathonParam: UniqueMarathonParam, entries: { donatedBy: string; @@ -29,7 +33,7 @@ export class DBFundsRepository { donatedOn: DateTime; amount: number; }[] - ): Promise> { + ): Promise> { try { const marathon = await this.marathonRepository.findMarathonByUnique(marathonParam); @@ -39,40 +43,44 @@ export class DBFundsRepository { await this.prisma.dBFundsTeam.upsert({ where: { dbNum_marathonId: { - dbNum, + dbNum: team.dbNum, marathonId: marathon.id, }, }, create: { - dbNum, - totalAmount: total, + dbNum: team.dbNum, + totalAmount: team.total, + active: team.active, + name: team.name, marathon: { connect: { id: marathon.id }, }, - entries: { + fundraisingEntries: { create: entries.map((entry) => ({ donatedBy: entry.donatedBy, donatedTo: entry.donatedTo.unwrapOr(null), - donatedOn: entry.donatedOn.toJSDate(), + date: entry.donatedOn.toJSDate(), amount: entry.amount, })), }, }, update: { - totalAmount: total, + totalAmount: team.total, + name: team.name, + active: team.active, fundraisingEntries: { deleteMany: {}, - createMany: { - data: entries.map((entry) => ({ - donatedBy: entry.donatedBy, - donatedTo: entry.donatedTo.unwrapOr(null), - date: entry.donatedOn.toJSDate(), - amount: entry.amount, - })), - }, + create: entries.map((entry) => ({ + donatedBy: entry.donatedBy, + donatedTo: entry.donatedTo.unwrapOr(null), + date: entry.donatedOn.toJSDate(), + amount: entry.amount, + })), }, }, }); + + return Result.ok(undefined); } catch (error) { return Result.err( toPrismaError(error).unwrapOrElse(() => asBasicError(error)) From 0faca3147bf957beb0e0982d15432355983ff7aa Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 31 May 2024 02:04:52 +0000 Subject: [PATCH 078/153] Add CompositeError class for handling multiple errors --- packages/server/src/lib/error/composite.ts | 22 ++++++++++++++++++++++ packages/server/src/lib/error/error.ts | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/lib/error/composite.ts diff --git a/packages/server/src/lib/error/composite.ts b/packages/server/src/lib/error/composite.ts new file mode 100644 index 00000000..814b74fc --- /dev/null +++ b/packages/server/src/lib/error/composite.ts @@ -0,0 +1,22 @@ +import { ConcreteError } from "./error.js"; + +export class CompositeError extends ConcreteError { + readonly errors: E[]; + + constructor(errors: E[]) { + super(); + this.errors = errors; + } + + get message(): string { + return this.errors.map((error) => error.message).join(", "); + } + + get detailedMessage(): string { + return this.errors.map((error) => error.detailedMessage).join(", "); + } + + get expose(): boolean { + return this.errors.every((error) => error.expose); + } +} diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index 4625ec06..b06fd7d1 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -52,6 +52,6 @@ export class UnknownError extends ConcreteError { export type BasicError = JsError | UnknownError; -export function asBasicError(error: unknown): BasicError { +export function toBasicError(error: unknown): BasicError { return error instanceof Error ? new JsError(error) : new UnknownError(error); } From d4b714cefdd75f9c67735246cf5a47e7bee16bb7 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 31 May 2024 02:05:05 +0000 Subject: [PATCH 079/153] Add syncDbFunds job for DBFunds synchronization --- packages/server/src/jobs/syncDbFunds.ts | 106 ++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 packages/server/src/jobs/syncDbFunds.ts diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts new file mode 100644 index 00000000..fe35959a --- /dev/null +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -0,0 +1,106 @@ +import type { Marathon } from "@prisma/client"; +import type { MarathonYearString } from "@ukdanceblue/common"; +import Cron from "croner"; +import { Result, type Unit } from "true-myth"; +import { Container } from "typedi"; + +import { CompositeError } from "../lib/error/composite.js"; +import { NotFoundError } from "../lib/error/direct.js"; +import { toBasicError } from "../lib/error/error.js"; +import type { PrismaError } from "../lib/error/prisma.js"; +import { toPrismaError } from "../lib/error/prisma.js"; +import { + DBFundsFundraisingProvider, + type DBFundsFundraisingProviderError, +} from "../lib/fundraising/DbFundsProvider.js"; +import { logger } from "../lib/logging/standardLogging.js"; +import { DBFundsRepository } from "../repositories/dbfunds/DBFundsRepository.js"; +import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; + +type DoSyncError = + | NotFoundError + | PrismaError + | DBFundsFundraisingProviderError; +async function doSync(): Promise< + Result> +> { + const marathonRepository = Container.get(MarathonRepository); + const fundraisingRepository = Container.get(DBFundsRepository); + const fundraisingProvider = Container.get(DBFundsFundraisingProvider); + let currentMarathon: Marathon | null = null; + try { + logger.trace("Finding current marathon for DBFunds sync"); + currentMarathon = await marathonRepository.findCurrentMarathon(); + logger.trace("Found current marathon for DBFunds sync", currentMarathon); + } catch (error) { + return Result.err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); + } + if (!currentMarathon) { + return Result.err( + new NotFoundError({ what: "Current Marathon", where: "syncDbFunds job" }) + ); + } + const teams = await fundraisingProvider.getTeams( + currentMarathon.year as MarathonYearString + ); + if (teams.isErr) { + return Result.err(teams.error); + } + logger.trace("Got teams for DBFunds sync", { teamCount: teams.value.length }); + + const promises = teams.value.map(async (team) => { + const entries = await fundraisingProvider.getTeamEntries( + currentMarathon.year as MarathonYearString, + team.identifier + ); + if (entries.isErr) { + return Result.err(entries.error); + } + return fundraisingRepository.overwriteTeamForFiscalYear( + { + active: team.active, + dbNum: team.identifier, + name: team.name, + total: team.total, + }, + { id: currentMarathon.id }, + entries.value + ); + }); + + const results = await Promise.allSettled(promises); + + const errors: DoSyncError[] = []; + for (const result of results) { + if (result.status === "rejected") { + errors.push(toBasicError(result.reason)); + } else if (result.value.isErr) { + errors.push(result.value.error); + } + } + + return errors.length > 0 + ? Result.err(new CompositeError(errors)) + : Result.ok(); +} + +export const syncDbFunds = new Cron( + "0 */11 * * * *", + { + name: "sync-db-funds", + catch: (error) => { + console.error("Failed to sync DBFunds", error); + }, + }, + async () => { + logger.info("Syncing DBFunds"); + const result = await doSync(); + if (result.isErr) { + logger.error("Failed to sync DBFunds", result.error); + } else { + logger.info("DBFunds sync complete"); + } + } +); From b56e337755b73e860a57584cde0238300c7af9de Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 31 May 2024 02:05:13 +0000 Subject: [PATCH 080/153] Refactor error handling in DBFundsFundraisingProvider and DBFundsRepository --- .../src/lib/fundraising/DbFundsProvider.ts | 18 ++++++--------- .../repositories/dbfunds/DBFundsRepository.ts | 22 ++++++++++++------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 7076d2c5..32f158af 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -8,7 +8,7 @@ import { dbFundsApiKeyToken, dbFundsApiOriginToken, } from "../../environment.js"; -import { JsError, UnknownError, asBasicError } from "../error/error.js"; +import { BasicError, toBasicError } from "../error/error.js"; import { HttpError } from "../error/http.js"; import { ConcreteResult } from "../error/result.js"; import { ZodError } from "../error/zod.js"; @@ -77,6 +77,8 @@ function teamEntriesPath( return `/api/report/teamentries/${dbNum}/${year}`; } +export type DBFundsFundraisingProviderError = HttpError | ZodError | BasicError; + @Service() export class DBFundsFundraisingProvider implements FundraisingProvider { constructor( @@ -88,7 +90,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { private async fetchJson( path: string | URL - ): Promise> { + ): Promise> { let response: Response; try { const url = new URL(path, this.dbFundsApiOrigin); @@ -98,7 +100,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { }, }); } catch (error) { - return Result.err(asBasicError(error)); + return Result.err(toBasicError(error)); } if (!response.ok) { @@ -111,10 +113,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { async getTeams( marathonYear: MarathonYearString ): Promise< - ConcreteResult< - FundraisingTeam[], - HttpError | JsError | UnknownError | ZodError - > + ConcreteResult[], DBFundsFundraisingProviderError> > { const calendarYear = `20${marathonYear.substring(2)}`; const path = teamTotalPath(calendarYear); @@ -141,10 +140,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { marathonYear: MarathonYearString, dbNum: number ): Promise< - ConcreteResult< - FundraisingEntry[], - HttpError | JsError | UnknownError | ZodError - > + ConcreteResult > { const calendarYear = `20${marathonYear.substring(2)}`; const path = teamEntriesPath(dbNum, calendarYear); diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts index c32ae762..8c876b0a 100644 --- a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts +++ b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts @@ -4,7 +4,7 @@ import { Maybe, Result } from "true-myth"; import { Service } from "typedi"; import { NotFoundError } from "../../lib/error/direct.js"; -import { asBasicError } from "../../lib/error/error.js"; +import { toBasicError } from "../../lib/error/error.js"; import { PrismaError, toPrismaError } from "../../lib/error/prisma.js"; import { type JsResult } from "../../lib/error/result.js"; import type { @@ -35,16 +35,22 @@ export class DBFundsRepository { }[] ): Promise> { try { - const marathon = - await this.marathonRepository.findMarathonByUnique(marathonParam); - if (!marathon) { - return Result.err(new NotFoundError({ what: "Marathon" })); + let marathonId: number; + if ("id" in marathonParam) { + marathonId = marathonParam.id; + } else { + const marathon = + await this.marathonRepository.findMarathonByUnique(marathonParam); + if (!marathon) { + return Result.err(new NotFoundError({ what: "Marathon" })); + } + marathonId = marathon.id; } await this.prisma.dBFundsTeam.upsert({ where: { dbNum_marathonId: { dbNum: team.dbNum, - marathonId: marathon.id, + marathonId, }, }, create: { @@ -53,7 +59,7 @@ export class DBFundsRepository { active: team.active, name: team.name, marathon: { - connect: { id: marathon.id }, + connect: { id: marathonId }, }, fundraisingEntries: { create: entries.map((entry) => ({ @@ -83,7 +89,7 @@ export class DBFundsRepository { return Result.ok(undefined); } catch (error) { return Result.err( - toPrismaError(error).unwrapOrElse(() => asBasicError(error)) + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) ); } } From 9a50b7b9edb2a435c881cbe73784cf9a34c5ac59 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 31 May 2024 02:34:12 +0000 Subject: [PATCH 081/153] Get dbfunds sync going --- packages/server/src/jobs/index.ts | 2 + packages/server/src/jobs/syncDbFunds.ts | 14 +++---- .../src/lib/fundraising/DbFundsProvider.ts | 40 +++++++++++-------- .../committee/CommitteeRepository.ts | 2 +- .../repositories/dbfunds/DBFundsRepository.ts | 10 ++--- .../marathon/MarathonRepository.ts | 3 +- .../server/src/resolvers/MarathonResolver.ts | 2 +- 7 files changed, 40 insertions(+), 33 deletions(-) diff --git a/packages/server/src/jobs/index.ts b/packages/server/src/jobs/index.ts index 7fe84d11..91751492 100644 --- a/packages/server/src/jobs/index.ts +++ b/packages/server/src/jobs/index.ts @@ -3,8 +3,10 @@ import { Container } from "typedi"; import { NotificationScheduler } from "./NotificationScheduler.js"; import { fetchPushReceipts } from "./fetchPushReceipts.js"; import { garbageCollectLoginFlowSessions } from "./garbageCollectLogins.js"; +import { syncDbFunds } from "./syncDbFunds.js"; await fetchPushReceipts.trigger(); await garbageCollectLoginFlowSessions.trigger(); +await syncDbFunds.trigger(); const scheduler = Container.get(NotificationScheduler); scheduler.ensureNotificationScheduler(); diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index fe35959a..3cc5dcd1 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -27,23 +27,23 @@ async function doSync(): Promise< const marathonRepository = Container.get(MarathonRepository); const fundraisingRepository = Container.get(DBFundsRepository); const fundraisingProvider = Container.get(DBFundsFundraisingProvider); - let currentMarathon: Marathon | null = null; + let activeMarathon: Marathon | null = null; try { logger.trace("Finding current marathon for DBFunds sync"); - currentMarathon = await marathonRepository.findCurrentMarathon(); - logger.trace("Found current marathon for DBFunds sync", currentMarathon); + activeMarathon = await marathonRepository.findActiveMarathon(); + logger.trace("Found current marathon for DBFunds sync", activeMarathon); } catch (error) { return Result.err( toPrismaError(error).unwrapOrElse(() => toBasicError(error)) ); } - if (!currentMarathon) { + if (!activeMarathon) { return Result.err( new NotFoundError({ what: "Current Marathon", where: "syncDbFunds job" }) ); } const teams = await fundraisingProvider.getTeams( - currentMarathon.year as MarathonYearString + activeMarathon.year as MarathonYearString ); if (teams.isErr) { return Result.err(teams.error); @@ -52,7 +52,7 @@ async function doSync(): Promise< const promises = teams.value.map(async (team) => { const entries = await fundraisingProvider.getTeamEntries( - currentMarathon.year as MarathonYearString, + activeMarathon.year as MarathonYearString, team.identifier ); if (entries.isErr) { @@ -65,7 +65,7 @@ async function doSync(): Promise< name: team.name, total: team.total, }, - { id: currentMarathon.id }, + { id: activeMarathon.id }, entries.value ); }); diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 32f158af..87b465c8 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -32,8 +32,11 @@ const dbFundsFundraisingTeamSchema = z.object({ .multipleOf(0.01, "Must be a whole number of cents"), }); +// Checks for any variation of "n/a" or "na" (case-insensitive) +const isNA = /^n\/?a$/i; + const dbFundsFundraisingEntrySchema = z.object({ - dbNum: z + dbnum: z .number() .describe("The dbNum of the team to which these entries belong") .int() @@ -47,12 +50,20 @@ const dbFundsFundraisingEntrySchema = z.object({ donatedTo: z .string() .describe("The name of the person or team who received the donation") - .transform((v) => (v === "N/A" ? null : v)) + .transform((v) => (isNA.test(v) ? null : v)) .nullable(), donatedOn: z .string() .describe("The date and time the donation was made, in Eastern time") - .datetime(), + // Checks for what passes for an ISO date in the DBFunds API + .transform((v) => + DateTime.fromISO(v, { + zone: "America/New_York", + }) + ) + .refine((v) => v.isValid, { + message: "Must be a valid ISO 8601 date", + }), // NOTE: Currently the API sends the amount as a number of cents (i.e. it sends 100.00 for $1.00) even though the total is // in dollars (i.e. it sends 1.00 for $1.00). This is a bit inconsistent, but it's not a big deal. We can just convert the // amount to dollars when we use it and this has already taken long enough to get going that I don't want to spend time @@ -150,22 +161,17 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { return result.cast(); } - const entries = dbFundsFundraisingEntrySchema - .array() - .safeParse(result.value); + const entries = dbFundsFundraisingEntrySchema.safeParse(result.value); if (entries.success) { return Result.ok( - entries.data.flatMap((team) => - team.entries.map((entry) => ({ - donatedBy: entry.donatedBy, - donatedTo: Maybe.of(entry.donatedTo), - // donatedOn is in Eastern time - donatedOn: DateTime.fromISO(entry.donatedOn, { - zone: "America/New_York", - }), - amount: entry.amount, - })) - ) + entries.data.entries.map((entry) => ({ + donatedBy: entry.donatedBy, + donatedTo: Maybe.of(entry.donatedTo), + // donatedOn is in Eastern time + donatedOn: entry.donatedOn, + // Convert the amount from cents to dollars + amount: entry.amount / 100, + })) ); } else { return Result.err(new ZodError(entries.error)); diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index dddb10c1..d458bd39 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -87,7 +87,7 @@ export class CommitteeRepository { } if (!marathonParam) { - const nextMarathon = await this.marathonRepository.findNextMarathon(); + const nextMarathon = await this.marathonRepository.findActiveMarathon(); if (!nextMarathon) { throw new DetailedError( ErrorCode.NotFound, diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts index 8c876b0a..c612dbd5 100644 --- a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts +++ b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts @@ -1,4 +1,4 @@ -import type { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "@prisma/client"; import type { DateTime } from "luxon"; import { Maybe, Result } from "true-myth"; import { Service } from "typedi"; @@ -7,10 +7,8 @@ import { NotFoundError } from "../../lib/error/direct.js"; import { toBasicError } from "../../lib/error/error.js"; import { PrismaError, toPrismaError } from "../../lib/error/prisma.js"; import { type JsResult } from "../../lib/error/result.js"; -import type { - MarathonRepository, - UniqueMarathonParam, -} from "../marathon/MarathonRepository.js"; +import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; +import { MarathonRepository } from "../marathon/MarathonRepository.js"; @Service() export class DBFundsRepository { @@ -75,6 +73,8 @@ export class DBFundsRepository { name: team.name, active: team.active, fundraisingEntries: { + // This deletes all existing entries, including ones from past years. This is intentional as it means we aren't persisting sensitive data that we won't be using anyways + // If it ever becomes desired to keep this data, simple filter the delete to only entries from the current marathon deleteMany: {}, create: entries.map((entry) => ({ donatedBy: entry.donatedBy, diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 37558023..4b93eafa 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -69,10 +69,9 @@ export class MarathonRepository { }); } - findNextMarathon() { + findActiveMarathon() { return this.prisma.marathon.findFirst({ orderBy: { year: "asc" }, - where: { endDate: { gte: new Date() } }, }); } diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index eb32c8b0..8fa34468 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -151,7 +151,7 @@ export class MarathonResolver @Query(() => MarathonNode, { nullable: true }) async nextMarathon() { - const marathon = await this.marathonRepository.findNextMarathon(); + const marathon = await this.marathonRepository.findActiveMarathon(); if (marathon == null) { return null; } From 06b320f1fc5ba2428b5bedcd9c73bc7f399d14f7 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 31 May 2024 02:48:29 +0000 Subject: [PATCH 082/153] Fix dbfunds on null donatedBy --- .../20240531023738_optional_donated_by/migration.sql | 2 ++ packages/server/prisma/schema.prisma | 2 +- packages/server/src/lib/fundraising/DbFundsProvider.ts | 8 ++++++-- .../server/src/lib/fundraising/FundraisingProvider.ts | 2 +- .../server/src/repositories/dbfunds/DBFundsRepository.ts | 6 +++--- 5 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 packages/server/prisma/migrations/20240531023738_optional_donated_by/migration.sql diff --git a/packages/server/prisma/migrations/20240531023738_optional_donated_by/migration.sql b/packages/server/prisma/migrations/20240531023738_optional_donated_by/migration.sql new file mode 100644 index 00000000..4a4d63f2 --- /dev/null +++ b/packages/server/prisma/migrations/20240531023738_optional_donated_by/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "db_funds_team_entries" ALTER COLUMN "donated_by" DROP NOT NULL; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index dc3f5850..c32040ef 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -435,7 +435,7 @@ model DBFundsFundraisingEntry { // The amount of the entry amount Decimal // Who made the donation - donatedBy String @map("donated_by") + donatedBy String? @map("donated_by") // Who the donation was made for donatedTo String? @map("donated_to") // The date of the donation diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 87b465c8..65e24911 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -46,7 +46,11 @@ const dbFundsFundraisingEntrySchema = z.object({ .describe("The name of the team to which these entries belong"), entries: z.array( z.object({ - donatedBy: z.string().describe("The name of the person who donated"), + donatedBy: z + .string() + .describe("The name of the person who donated") + .transform((v) => (isNA.test(v) ? null : v)) + .nullable(), donatedTo: z .string() .describe("The name of the person or team who received the donation") @@ -165,7 +169,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { if (entries.success) { return Result.ok( entries.data.entries.map((entry) => ({ - donatedBy: entry.donatedBy, + donatedBy: Maybe.of(entry.donatedBy), donatedTo: Maybe.of(entry.donatedTo), // donatedOn is in Eastern time donatedOn: entry.donatedOn, diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index 5de0f422..23815d9c 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -14,7 +14,7 @@ export interface FundraisingTeam { } export interface FundraisingEntry { - donatedBy: string; + donatedBy: Maybe; donatedTo: Maybe; donatedOn: DateTime; amount: number; diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts index c612dbd5..75f18e78 100644 --- a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts +++ b/packages/server/src/repositories/dbfunds/DBFundsRepository.ts @@ -26,7 +26,7 @@ export class DBFundsRepository { }, marathonParam: UniqueMarathonParam, entries: { - donatedBy: string; + donatedBy: Maybe; donatedTo: Maybe; donatedOn: DateTime; amount: number; @@ -61,7 +61,7 @@ export class DBFundsRepository { }, fundraisingEntries: { create: entries.map((entry) => ({ - donatedBy: entry.donatedBy, + donatedBy: entry.donatedBy.unwrapOr(null), donatedTo: entry.donatedTo.unwrapOr(null), date: entry.donatedOn.toJSDate(), amount: entry.amount, @@ -77,7 +77,7 @@ export class DBFundsRepository { // If it ever becomes desired to keep this data, simple filter the delete to only entries from the current marathon deleteMany: {}, create: entries.map((entry) => ({ - donatedBy: entry.donatedBy, + donatedBy: entry.donatedBy.unwrapOr(null), donatedTo: entry.donatedTo.unwrapOr(null), date: entry.donatedOn.toJSDate(), amount: entry.amount, From eb1c41ed67c71fb34b7996c3701ceeb25695e0bf Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 1 Jun 2024 17:27:52 +0000 Subject: [PATCH 083/153] Refactor DBFundsFundraisingProvider and DBFundsRepository --- .../common/lib/api/resources/Fundraising.ts | 56 +++++++++++++++++++ packages/server/src/jobs/syncDbFunds.ts | 2 +- .../DBFundsRepository.ts | 0 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/common/lib/api/resources/Fundraising.ts rename packages/server/src/repositories/{dbfunds => fundraising}/DBFundsRepository.ts (100%) diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts new file mode 100644 index 00000000..6d10556f --- /dev/null +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -0,0 +1,56 @@ +import { DateTimeISOResolver } from "graphql-scalars"; +import type { DateTime } from "luxon"; +import { Field, Float, ID, ObjectType } from "type-graphql"; + +import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; +import { Node } from "../relay.js"; + +import { TimestampedResource } from "./Resource.js"; + +@ObjectType({ + implements: [Node], +}) +export class FundraisingEntryNode extends TimestampedResource implements Node { + @Field(() => ID) + id!: string; + @Field(() => String) + donatedByText!: string; + @Field(() => String) + donatedToText!: string; + @Field(() => DateTimeISOResolver) + start!: Date; + get startDateTime(): DateTime { + return dateTimeFromSomething(this.start); + } + @Field(() => Float) + amount!: number; + + public getUniqueId(): string { + return this.id; + } + + public static init(init: Partial) { + return FundraisingEntryNode.doInit(init); + } +} + +@ObjectType({ + implements: [Node], +}) +export class FundraisingAssignmentNode + extends TimestampedResource + implements Node +{ + @Field(() => ID) + id!: string; + @Field(() => Float) + amount!: number; + + public getUniqueId(): string { + return this.id; + } + + public static init(init: Partial) { + return FundraisingAssignmentNode.doInit(init); + } +} diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index 3cc5dcd1..2f9d94b3 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -14,7 +14,7 @@ import { type DBFundsFundraisingProviderError, } from "../lib/fundraising/DbFundsProvider.js"; import { logger } from "../lib/logging/standardLogging.js"; -import { DBFundsRepository } from "../repositories/dbfunds/DBFundsRepository.js"; +import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; type DoSyncError = diff --git a/packages/server/src/repositories/dbfunds/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts similarity index 100% rename from packages/server/src/repositories/dbfunds/DBFundsRepository.ts rename to packages/server/src/repositories/fundraising/DBFundsRepository.ts From 886c40d888fa3b8da0782f0e0741132701a23eac Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 02:14:01 +0000 Subject: [PATCH 084/153] Add FundraisingAssignment and FundraisingEntry resolvers --- packages/common/lib/api/resources/index.ts | 1 + .../FundraisingAssignmentResolver.ts | 63 +++++++++++++++++++ .../src/resolvers/FundraisingEntryResolver.ts | 54 ++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 packages/server/src/resolvers/FundraisingAssignmentResolver.ts create mode 100644 packages/server/src/resolvers/FundraisingEntryResolver.ts diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index 1e14c754..de0c2d59 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -7,6 +7,7 @@ export * from "./Configuration.js"; export * from "./Device.js"; export * from "./Event.js"; export * from "./Feed.js"; +export * from "./Fundraising.js"; export * from "./Image.js"; export * from "./Marathon.js"; export * from "./MarathonHour.js"; diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts new file mode 100644 index 00000000..e6748bc8 --- /dev/null +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -0,0 +1,63 @@ +import { + FundraisingAssignmentNode, + FundraisingEntryNode, + PersonNode, +} from "@ukdanceblue/common"; +import { + Arg, + FieldResolver, + Mutation, + Query, + Resolver, + Root, +} from "type-graphql"; +import { Service } from "typedi"; + +@Resolver(() => FundraisingAssignmentNode) +@Service() +export class FundraisingAssignmentResolver { + constructor(private readonly fundraisingRepository: FundraisingRepository) {} + + @Query(() => FundraisingAssignmentNode) + async fundraisingAssignment( + @Arg("id") id: string + ): Promise { + // TODO + } + + @Mutation(() => FundraisingAssignmentNode) + async createFundraisingAssignment( + @Arg("input") input: CreateFundraisingAssignmentInput + ): Promise { + // TODO + } + + @Mutation(() => FundraisingAssignmentNode) + async updateFundraisingAssignment( + @Arg("id") id: string, + @Arg("input") input: UpdateFundraisingAssignmentInput + ): Promise { + // TODO + } + + @Mutation(() => FundraisingAssignmentNode) + async deleteFundraisingAssignment( + @Arg("id") id: string + ): Promise { + // TODO + } + + @FieldResolver(() => FundraisingEntryNode) + async entry( + @Root() assignment: FundraisingAssignmentNode + ): Promise { + // TODO + } + + @FieldResolver(() => PersonNode) + async person( + @Root() assignment: FundraisingAssignmentNode + ): Promise { + // TODO + } +} diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts new file mode 100644 index 00000000..a99cc090 --- /dev/null +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -0,0 +1,54 @@ +import { + FundraisingAssignmentNode, + FundraisingEntryNode, +} from "@ukdanceblue/common"; +import { + Arg, + FieldResolver, + Mutation, + Query, + Resolver, + Root, +} from "type-graphql"; +import { Service } from "typedi"; + +@Resolver(() => FundraisingEntryNode) +@Service() +export class FundraisingEntryResolver { + constructor(private readonly fundraisingRepository: FundraisingRepository) {} + + @Query(() => FundraisingEntryNode) + async fundraisingEntry(@Arg("id") id: string): Promise { + // TODO + } + + @Mutation(() => FundraisingEntryNode) + async createFundraisingEntry( + @Arg("input") input: CreateFundraisingEntryInput, + @Arg("teamId") teamId: string + ): Promise { + // TODO + } + + @Mutation(() => FundraisingEntryNode) + async updateFundraisingEntry( + @Arg("id") id: string, + @Arg("input") input: UpdateFundraisingEntryInput + ): Promise { + // TODO + } + + @Mutation(() => FundraisingEntryNode) + async deleteFundraisingEntry( + @Arg("id") id: string + ): Promise { + // TODO + } + + @FieldResolver(() => [FundraisingAssignmentNode]) + async assignments( + @Root() entry: FundraisingEntryNode + ): Promise { + // TODO + } +} From aa5ced0307439c21138d41fa834fcdde81bf98c4 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 03:48:24 +0000 Subject: [PATCH 085/153] Refactor FundraisingEntry and FundraisingAssignment classes --- packages/common/lib/api/resources/Fundraising.ts | 14 +++++++++++++- .../fundraising/FundraisingAssignmentRepository.ts | 0 .../fundraising/FundraisingEntryRepository.ts | 0 .../fundraisingAssignmentModelToNode.ts | 0 .../fundraising/fundraisingEntryModelToNode.ts | 0 .../fundraising/fundraisingEntryRepositoryUtils.ts | 0 6 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts create mode 100644 packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts create mode 100644 packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts create mode 100644 packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts create mode 100644 packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts index 6d10556f..41840394 100644 --- a/packages/common/lib/api/resources/Fundraising.ts +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -3,7 +3,7 @@ import type { DateTime } from "luxon"; import { Field, Float, ID, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; -import { Node } from "../relay.js"; +import { Node, createNodeClasses } from "../relay.js"; import { TimestampedResource } from "./Resource.js"; @@ -34,6 +34,12 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { } } +export const { + FundraisingEntryConnection, + FundraisingEntryEdge, + FundraisingEntryResult, +} = createNodeClasses(FundraisingEntryNode, "FundraisingEntry"); + @ObjectType({ implements: [Node], }) @@ -54,3 +60,9 @@ export class FundraisingAssignmentNode return FundraisingAssignmentNode.doInit(init); } } + +export const { + FundraisingAssignmentConnection, + FundraisingAssignmentEdge, + FundraisingAssignmentResult, +} = createNodeClasses(FundraisingAssignmentNode, "FundraisingAssignment"); diff --git a/packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts b/packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts b/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts b/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts b/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts new file mode 100644 index 00000000..e69de29b From 257dfca7eb718657f1ca8c09acc5a5b99b760903 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 20:54:53 +0000 Subject: [PATCH 086/153] Write the fundraising repository --- .../FundraisingAssignmentRepository.ts | 0 .../fundraising/FundraisingEntryRepository.ts | 353 ++++++++++++++++++ .../fundraisingEntryRepositoryUtils.ts | 100 +++++ 3 files changed, 453 insertions(+) delete mode 100644 packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts diff --git a/packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts b/packages/server/src/repositories/fundraising/FundraisingAssignmentRepository.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts b/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts index e69de29b..b1391c0d 100644 --- a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts @@ -0,0 +1,353 @@ +import { + DBFundsFundraisingEntry, + FundraisingAssignment, + FundraisingEntry, + Prisma, + PrismaClient, +} from "@prisma/client"; +import type { SortDirection } from "@ukdanceblue/common"; +import Maybe, { just, nothing, of } from "true-myth/maybe"; +import Result, { err, ok } from "true-myth/result"; +import { Service } from "typedi"; + +import { ActionDeniedError } from "../../lib/error/control.js"; +import { NotFoundError } from "../../lib/error/direct.js"; +import { BasicError, toBasicError } from "../../lib/error/error.js"; +import { SomePrismaError, toPrismaError } from "../../lib/error/prisma.js"; +import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { SimpleUniqueParam } from "../shared.js"; + +import { + buildFundraisingEntryOrder, + buildFundraisingEntryWhere, +} from "./fundraisingEntryRepositoryUtils.js"; + +const fundraisingEntryBooleanKeys = [] as const; +type FundraisingEntryBooleanKey = (typeof fundraisingEntryBooleanKeys)[number]; + +const fundraisingEntryDateKeys = [ + "donatedOn", + "createdAt", + "updatedAt", +] as const; +type FundraisingEntryDateKey = (typeof fundraisingEntryDateKeys)[number]; + +const fundraisingEntryIsNullKeys = [] as const; +type FundraisingEntryIsNullKey = (typeof fundraisingEntryIsNullKeys)[number]; + +const fundraisingEntryNumericKeys = ["amount"] as const; +type FundraisingEntryNumericKey = (typeof fundraisingEntryNumericKeys)[number]; + +const fundraisingEntryOneOfKeys = [] as const; +type FundraisingEntryOneOfKey = (typeof fundraisingEntryOneOfKeys)[number]; + +const fundraisingEntryStringKeys = ["donatedTo", "donatedBy"] as const; +type FundraisingEntryStringKey = (typeof fundraisingEntryStringKeys)[number]; + +export type FundraisingEntryOrderKeys = + | "donatedOn" + | "amount" + | "donatedTo" + | "donatedBy" + | "createdAt" + | "updatedAt"; + +export type FundraisingEntryFilters = FilterItems< + FundraisingEntryBooleanKey, + FundraisingEntryDateKey, + FundraisingEntryIsNullKey, + FundraisingEntryNumericKey, + FundraisingEntryOneOfKey, + FundraisingEntryStringKey +>; + +const defaultInclude = { + dbFundsEntry: true, +} satisfies Prisma.FundraisingEntryInclude; + +export type FundraisingEntryUniqueParam = SimpleUniqueParam; +export type FundraisingAssignmentUniqueParam = SimpleUniqueParam; + +@Service() +export class FundraisingEntryRepository { + constructor(private readonly prisma: PrismaClient) {} + + async findFundraisingEntryByUnique( + param: FundraisingEntryUniqueParam + ): Promise< + Result< + Maybe< + FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry | null } + >, + SomePrismaError | BasicError + > + > { + try { + return ok( + of( + await this.prisma.fundraisingEntry.findUnique({ + where: param, + include: defaultInclude, + }) + ) + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async getFundraisingAssignmentsForEntry( + param: FundraisingEntryUniqueParam + ): Promise< + Result< + Maybe, + SomePrismaError | BasicError + > + > { + try { + const entry = await this.prisma.fundraisingEntry.findUnique({ + where: param, + select: { assignments: true }, + }); + return ok(of(entry?.assignments)); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async listFundraisingEntries({ + filters, + order, + skip, + take, + }: { + filters?: readonly FundraisingEntryFilters[] | undefined | null; + order?: + | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] + | undefined + | null; + skip?: number | undefined | null; + take?: number | undefined | null; + }): Promise< + Result< + readonly (FundraisingEntry & { + dbFundsEntry: DBFundsFundraisingEntry | null; + })[], + SomePrismaError | BasicError + > + > { + try { + const where = buildFundraisingEntryWhere(filters); + const orderBy = buildFundraisingEntryOrder(order); + + return ok( + await this.prisma.fundraisingEntry.findMany({ + include: defaultInclude, + where, + orderBy, + skip: skip ?? undefined, + take: take ?? undefined, + }) + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async countFundraisingEntries({ + filters, + }: { + filters?: readonly FundraisingEntryFilters[] | undefined | null; + }): Promise> { + try { + const where = buildFundraisingEntryWhere(filters); + + return ok(await this.prisma.fundraisingEntry.count({ where })); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async connectFundraisingEntry( + dbFundsEntry: DBFundsFundraisingEntry + ): Promise< + Result + > { + try { + const row = await this.prisma.fundraisingEntry.upsert({ + where: { id: dbFundsEntry.id }, + update: {}, + create: { + dbFundsEntry: { + connect: { id: dbFundsEntry.id }, + }, + }, + }); + return ok({ + id: row.id, + }); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async deleteFundraisingEntry( + param: FundraisingEntryUniqueParam + ): Promise, SomePrismaError | BasicError>> { + try { + return ok( + just(await this.prisma.fundraisingEntry.delete({ where: param })) + ); + } catch (error) { + if ( + error instanceof Prisma.PrismaClientKnownRequestError && + error.code === "P2025" + ) { + return ok(nothing()); + } else { + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); + } + } + } + + async addAssignmentToFundraisingEntry( + entryParam: FundraisingEntryUniqueParam, + personParam: SimpleUniqueParam, + { amount }: { amount: number } + ): Promise< + Result< + FundraisingAssignment, + SomePrismaError | BasicError | NotFoundError | ActionDeniedError + > + > { + try { + const entry = await this.findFundraisingEntryByUnique(entryParam); + if (entry.isErr) { + return err(entry.error); + } else if (entry.value.isNothing) { + return err(new NotFoundError({ what: "FundraisingEntry" })); + } + const assignments = + await this.getFundraisingAssignmentsForEntry(entryParam); + if (assignments.isErr) { + return err(assignments.error); + } else if (assignments.value.isNothing) { + return err(new NotFoundError({ what: "FundraisingEntry" })); + } + + if (!entry.value.value.dbFundsEntry) { + return err( + new ActionDeniedError("Entry is not connected to a DBFunds entry") + ); + } + + const totalAssigned = assignments.value.value.reduce( + (acc, assignment) => acc.add(assignment.amount), + new Prisma.Decimal(0) + ); + if ( + entry.value.value.dbFundsEntry.amount.lessThan( + totalAssigned.add(amount) + ) + ) { + return err( + new ActionDeniedError("Total assigned amount exceeds entry amount") + ); + } + + return ok( + await this.prisma.fundraisingAssignment.create({ + data: { + amount, + parentEntry: { connect: entryParam }, + person: { connect: personParam }, + }, + }) + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async removeAssignmentFromFundraisingEntry( + assignmentParam: FundraisingAssignmentUniqueParam + ): Promise< + Result + > { + try { + return ok( + await this.prisma.fundraisingAssignment.delete({ + where: assignmentParam, + }) + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async updateAssignment( + assignmentParam: FundraisingAssignmentUniqueParam, + { amount }: { amount: number } + ): Promise< + Result< + FundraisingAssignment, + SomePrismaError | BasicError | NotFoundError | ActionDeniedError + > + > { + try { + const assignment = await this.prisma.fundraisingAssignment.findUnique({ + where: assignmentParam, + select: { + id: true, + parentEntry: { + select: { dbFundsEntry: { select: { amount: true } }, id: true }, + }, + }, + }); + if (!assignment) { + return err(new NotFoundError({ what: "FundraisingEntry" })); + } + const assignments = await this.getFundraisingAssignmentsForEntry({ + id: assignment.parentEntry.id, + }); + if (assignments.isErr) { + return err(assignments.error); + } else if (assignments.value.isNothing) { + return err(new NotFoundError({ what: "FundraisingEntry" })); + } + + if (!assignment.parentEntry.dbFundsEntry) { + return err( + new ActionDeniedError("Entry is not connected to a DBFunds entry") + ); + } + + const totalAssigned = assignments.value.value + .filter((a) => a.id !== assignment.id) + .reduce( + (acc, assignment) => acc.add(assignment.amount), + new Prisma.Decimal(0) + ); + if ( + assignment.parentEntry.dbFundsEntry.amount.lessThan( + totalAssigned.add(amount) + ) + ) { + return err( + new ActionDeniedError("Total assigned amount exceeds entry amount") + ); + } + + return ok( + await this.prisma.fundraisingAssignment.update({ + where: assignmentParam, + data: { amount }, + }) + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } +} diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index e69de29b..ae5da4a1 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -0,0 +1,100 @@ +import type { Prisma } from "@prisma/client"; +import { SortDirection } from "@ukdanceblue/common"; + +import { + dateFilterToPrisma, + numericFilterToPrisma, + stringFilterToPrisma, +} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; + +import type { + FundraisingEntryFilters, + FundraisingEntryOrderKeys, +} from "./FundraisingEntryRepository.ts"; + +export function buildFundraisingEntryOrder( + order: + | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] + | null + | undefined +) { + const orderBy: Prisma.FundraisingEntryOrderByWithRelationInput = {}; + const dbFundsEntryOrderBy: Prisma.FundraisingEntryOrderByWithRelationInput["dbFundsEntry"] = + {}; + + for (const [key, sort] of order ?? []) { + switch (key) { + case "donatedOn": { + dbFundsEntryOrderBy["date"] = + sort === SortDirection.asc ? "asc" : "desc"; + break; + } + case "amount": + case "donatedTo": + case "donatedBy": { + dbFundsEntryOrderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; + break; + } + case "createdAt": + case "updatedAt": { + orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; + break; + } + default: { + key satisfies never; + throw new Error(`Unsupported sort key: ${String(key)}`); + } + } + } + + if (Object.keys(dbFundsEntryOrderBy).length > 0) { + orderBy["dbFundsEntry"] = dbFundsEntryOrderBy; + } + + return orderBy; +} + +export function buildFundraisingEntryWhere( + filters: readonly FundraisingEntryFilters[] | null | undefined +) { + const where: Prisma.FundraisingEntryWhereInput = {}; + const dbFundsEntryWhere: Prisma.FundraisingEntryWhereInput["dbFundsEntry"] = + {}; + + for (const filter of filters ?? []) { + switch (filter.field) { + case "updatedAt": + case "createdAt": { + where[filter.field] = dateFilterToPrisma(filter); + break; + } + case "amount": { + dbFundsEntryWhere[filter.field] = numericFilterToPrisma(filter); + break; + } + case "donatedOn": { + dbFundsEntryWhere["date"] = dateFilterToPrisma(filter); + break; + } + case "donatedTo": + case "donatedBy": { + dbFundsEntryWhere[filter.field] = stringFilterToPrisma(filter); + break; + } + default: { + filter satisfies never; + throw new Error( + `Unsupported filter key: ${String( + (filter as { field?: string } | undefined)?.field + )}` + ); + } + } + } + + if (Object.keys(dbFundsEntryWhere).length > 0) { + where["dbFundsEntry"] = dbFundsEntryWhere; + } + + return where; +} From f6b3fcced04feaba64f39862ca5b12a43fc6c400 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 20:55:19 +0000 Subject: [PATCH 087/153] Add ControlError and related classes for error handling --- packages/server/src/lib/error/control.ts | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 packages/server/src/lib/error/control.ts diff --git a/packages/server/src/lib/error/control.ts b/packages/server/src/lib/error/control.ts new file mode 100644 index 00000000..fda22203 --- /dev/null +++ b/packages/server/src/lib/error/control.ts @@ -0,0 +1,54 @@ +import type { AuthorizationRule } from "@ukdanceblue/common"; +import { prettyPrintAuthorizationRule } from "@ukdanceblue/common"; + +import { ConcreteError } from "./error.js"; + +/** + * These errors are caused when the server can do something, but doesn't want to. For example + * when a user tries to do something they aren't allowed to do, or when a notification is cancelled + * after it's already been sent. + * + * Exposed by default. + */ +export abstract class ControlError extends ConcreteError { + abstract get message(): string; + get detailedMessage(): string { + return this.message; + } + get expose() { + return true; + } + get stack(): string | undefined { + return undefined; + } +} + +export class UnauthorizedError extends ControlError { + get message() { + return "Unauthorized"; + } + + constructor(protected readonly requiredAuthorization: AuthorizationRule[]) { + super(); + } + + get detailedMessage() { + return `Unauthorized: ${this.requiredAuthorization.map(prettyPrintAuthorizationRule).join(", ")}`; + } +} + +export class UnauthenticatedError extends ControlError { + get message() { + return "Unauthenticated"; + } +} + +export class ActionDeniedError extends ControlError { + constructor(protected readonly action: string) { + super(); + } + + get message() { + return `Action denied: ${this.action}`; + } +} From 9e6ee54d45c1d86c6d3144fdc12085d335d183f6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 20:55:53 +0000 Subject: [PATCH 088/153] Extract SomePrismaError type to alias --- packages/server/src/lib/error/prisma.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts index f9f041f2..ac0297ff 100644 --- a/packages/server/src/lib/error/prisma.ts +++ b/packages/server/src/lib/error/prisma.ts @@ -82,15 +82,14 @@ export class PrismaValidationError extends PrismaError { } } -export function toPrismaError( - error: unknown -): Maybe< +export type SomePrismaError = | PrismaInitializationError | PrismaKnownRequestError | PrismaRustPanicError | PrismaUnknownRequestError - | PrismaValidationError -> { + | PrismaValidationError; + +export function toPrismaError(error: unknown): Maybe { if (error instanceof PrismaClientInitializationError) { return Maybe.of(new PrismaInitializationError(error)); } From 772395ce7ce12c80e1008a7e1b981472f0bd282d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 20:56:17 +0000 Subject: [PATCH 089/153] Remove preferTypeOnlyAutoImports --- .vscode/settings.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 07a4092f..b02545f4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,6 @@ }, "remote.localPortHost": "allInterfaces", "typescript.inlayHints.parameterNames.enabled": "all", - "typescript.preferences.preferTypeOnlyAutoImports": true, "javascript.inlayHints.parameterNames.enabled": "all", "cSpell.words": [ "cooldown", From 66e4c21b10bad582b58e586d62bb2e4cb3bbb848 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 21:23:08 +0000 Subject: [PATCH 090/153] Add model to node functions --- .../fundraisingAssignmentModelToNode.ts | 15 ++++++++++++++ .../fundraisingEntryModelToNode.ts | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts b/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts index e69de29b..49eada8a 100644 --- a/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts +++ b/packages/server/src/repositories/fundraising/fundraisingAssignmentModelToNode.ts @@ -0,0 +1,15 @@ +import type { FundraisingAssignment } from "@prisma/client"; +import { FundraisingAssignmentNode } from "@ukdanceblue/common"; + +export function fundraisingAssignmentModelToNode( + marathonHourModel: FundraisingAssignment +): Promise { + return Promise.resolve( + FundraisingAssignmentNode.init({ + id: marathonHourModel.uuid, + amount: marathonHourModel.amount.toNumber(), + createdAt: marathonHourModel.createdAt, + updatedAt: marathonHourModel.updatedAt, + }) + ); +} diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts b/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts index e69de29b..08e64208 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts @@ -0,0 +1,20 @@ +import type { DBFundsFundraisingEntry, FundraisingEntry } from "@prisma/client"; +import { FundraisingEntryNode } from "@ukdanceblue/common"; + +export function fundraisingEntryModelToNode( + marathonHourModel: FundraisingEntry & { + dbFundsEntry: DBFundsFundraisingEntry; + } +): Promise { + return Promise.resolve( + FundraisingEntryNode.init({ + id: marathonHourModel.uuid, + amount: marathonHourModel.dbFundsEntry.amount.toNumber(), + donatedByText: marathonHourModel.dbFundsEntry.donatedBy, + donatedToText: marathonHourModel.dbFundsEntry.donatedTo, + donatedOn: marathonHourModel.dbFundsEntry.date, + createdAt: marathonHourModel.createdAt, + updatedAt: marathonHourModel.updatedAt, + }) + ); +} From d363db4a6cb2f25755e7337f9b3adf973e1514a2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 21:23:32 +0000 Subject: [PATCH 091/153] Add true-myth to common --- packages/common/package.json | 3 ++- yarn.lock | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/common/package.json b/packages/common/package.json index 3b420dec..7788a0c6 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -74,6 +74,7 @@ }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781", "dependencies": { - "htmlparser2": "^9.1.0" + "htmlparser2": "^9.1.0", + "true-myth": "^7.3.0" } } diff --git a/yarn.lock b/yarn.lock index 97b2902a..8de481fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8360,6 +8360,7 @@ __metadata: "@types/validator": "npm:^13.7.17" htmlparser2: "npm:^9.1.0" jest: "npm:^29.5.0" + true-myth: "npm:^7.3.0" ts-jest: "npm:^29.1.0" ts-node: "npm:^10.9.1" typescript: "npm:^5.4.3" From ecc9e9effd62ffd233e6658020cb699846153fa9 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 21:23:48 +0000 Subject: [PATCH 092/153] Add prettyPrintAuthorizationRule function --- .../common/lib/authorization/accessControl.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 971acc2f..25e83691 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -63,6 +63,37 @@ export interface AuthorizationRule { custom?: (authorization: Authorization) => boolean; } +export function prettyPrintAuthorizationRule(rule: AuthorizationRule): string { + const parts: string[] = []; + if (rule.accessLevel != null) { + parts.push(`accessLevel >= ${rule.accessLevel}`); + } + if (rule.dbRole != null) { + parts.push(`dbRole === ${rule.dbRole}`); + } + if (rule.minDbRole != null) { + parts.push(`dbRole >= ${rule.minDbRole}`); + } + // if (rule.committeeRole != null) { + // parts.push(`committeeRole === ${rule.committeeRole}`); + // } + if (rule.minCommitteeRole != null) { + parts.push(`committeeRole >= ${rule.minCommitteeRole}`); + } + if (rule.committeeIdentifier != null) { + parts.push(`committeeIdentifier === ${rule.committeeIdentifier}`); + } + if (rule.committeeIdentifiers != null) { + parts.push( + `committeeIdentifier in ${rule.committeeIdentifiers.join(", ")}` + ); + } + if (rule.custom != null) { + parts.push(`[custom]`); + } + return parts.join(", "); +} + export function checkAuthorization( { accessLevel, From 5a626301bc36a6b26a84b5cd005e35e8472aea02 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 21:24:05 +0000 Subject: [PATCH 093/153] Fix fundraising node classes --- .../common/lib/api/resources/Fundraising.ts | 66 ++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts index 41840394..4a6b87ca 100644 --- a/packages/common/lib/api/resources/Fundraising.ts +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -1,5 +1,7 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; +import { Maybe } from "true-myth"; +import { nothing, of } from "true-myth/maybe"; import { Field, Float, ID, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; @@ -13,14 +15,26 @@ import { TimestampedResource } from "./Resource.js"; export class FundraisingEntryNode extends TimestampedResource implements Node { @Field(() => ID) id!: string; - @Field(() => String) - donatedByText!: string; - @Field(() => String) - donatedToText!: string; + @Field(() => String, { nullable: true, name: "donatedByText" }) + private _donatedByText!: string | null; + get donatedByText(): Maybe { + return of(this._donatedByText); + } + set donatedByText(value: Maybe) { + this._donatedByText = value.unwrapOr(null); + } + @Field(() => String, { nullable: true, name: "donatedToText" }) + private _donatedToText!: string | null; + get donatedToText(): Maybe { + return of(this._donatedToText); + } + set donatedToText(value: Maybe) { + this._donatedToText = value.unwrapOr(null); + } @Field(() => DateTimeISOResolver) - start!: Date; - get startDateTime(): DateTime { - return dateTimeFromSomething(this.start); + donatedOn!: Date; + get donatedOnDateTime(): DateTime { + return dateTimeFromSomething(this.donatedOn); } @Field(() => Float) amount!: number; @@ -29,8 +43,35 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { return this.id; } - public static init(init: Partial) { - return FundraisingEntryNode.doInit(init); + public static init(init: { + id: string; + donatedByText: Maybe | string | null; + donatedToText: Maybe | string | null; + donatedOn: Date; + amount: number; + createdAt: Date; + updatedAt: Date; + }) { + const node = new FundraisingEntryNode(); + node.id = init.id; + node.donatedByText = + init.donatedByText == null + ? nothing() + : typeof init.donatedByText === "string" + ? of(init.donatedByText) + : init.donatedByText; + node.donatedToText = + init.donatedToText == null + ? nothing() + : typeof init.donatedToText === "string" + ? of(init.donatedToText) + : init.donatedToText; + node.donatedOn = init.donatedOn; + node.amount = init.amount; + node.createdAt = init.createdAt; + node.updatedAt = init.updatedAt; + + return node; } } @@ -56,7 +97,12 @@ export class FundraisingAssignmentNode return this.id; } - public static init(init: Partial) { + public static init(init: { + id: string; + amount: number; + createdAt: Date; + updatedAt: Date; + }) { return FundraisingAssignmentNode.doInit(init); } } From 76624de26638e92d61cf20ce1fc6d2e9195d7576 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 5 Jun 2024 21:38:28 +0000 Subject: [PATCH 094/153] Start on resolvers for fundraising --- .vscode/settings.json | 1 + packages/server/prisma/schema.prisma | 16 ++--- packages/server/src/lib/formatError.ts | 28 ++++++++- .../fundraising/FundraisingEntryRepository.ts | 57 +++++++---------- .../FundraisingAssignmentResolver.ts | 10 +-- .../src/resolvers/FundraisingEntryResolver.ts | 63 +++++++++---------- 6 files changed, 93 insertions(+), 82 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b02545f4..342b2aa1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,6 +19,7 @@ "typescript.inlayHints.parameterNames.enabled": "all", "javascript.inlayHints.parameterNames.enabled": "all", "cSpell.words": [ + "Catchable", "cooldown", "Errorable", "Leaderboards", diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index c32040ef..8a6a2974 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -447,24 +447,20 @@ model DBFundsFundraisingEntry { // The corresponding fundraising entry in our database fundraisingEntry FundraisingEntry? - @@unique([donatedBy, date], map: "db_funds_team_entries_donated_by_date_key") @@map("db_funds_team_entries") } model FundraisingEntry { - id Int @id @default(autoincrement()) - uuid String @unique(map: "fundraising_entries_uuid_unique") @default(uuid()) @db.Uuid - createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - totalAmount Decimal @map("total_amount") + id Int @id @default(autoincrement()) + uuid String @unique(map: "fundraising_entries_uuid_unique") @default(uuid()) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - dbFundsEntry DBFundsFundraisingEntry? @relation(references: [donatedBy, date], fields: [dbFundsEntryDonatedBy, dbFundsEntryDate], onDelete: SetNull) - dbFundsEntryDonatedBy String? @map("db_funds_entry_donated_by") - dbFundsEntryDate DateTime? @map("db_funds_entry_date") + dbFundsEntry DBFundsFundraisingEntry? @relation(fields: [dbFundsEntryId], references: [id], onDelete: SetNull) + dbFundsEntryId Int? @unique @map("db_funds_entry_id") assignments FundraisingAssignment[] - @@unique([dbFundsEntryDonatedBy, dbFundsEntryDate], map: "fundraising_entries_db_funds_entry_donated_by_date_key") @@index([uuid], map: "fundraising_entries_uuid") @@map("fundraising_entries") } diff --git a/packages/server/src/lib/formatError.ts b/packages/server/src/lib/formatError.ts index d69a4fcd..3d3219b1 100644 --- a/packages/server/src/lib/formatError.ts +++ b/packages/server/src/lib/formatError.ts @@ -14,12 +14,23 @@ import { GraphQLError } from "graphql"; import jwt from "jsonwebtoken"; import type { Writable } from "utility-types"; +import type { ConcreteError } from "./error/error.js"; + export interface DbGraphQLFormattedErrorExtensions extends Omit { internalDetails?: Record; stacktrace?: string[]; } +export class CatchableConcreteError extends Error { + declare cause: ConcreteError; + constructor(error: ConcreteError) { + super(error.message); + this.cause = error; + this.stack = error.stack; + } +} + /** * * @param originalFormattedError @@ -59,7 +70,22 @@ export function formatError( formattedError.extensions.stacktrace = error.stack?.split("\n") ?? []; } - if (error instanceof DetailedError) { + if (error instanceof CatchableConcreteError) { + const { message, detailedMessage, expose, stack } = error.cause; + formattedError.message = message; + if (expose) { + formattedError.extensions.stacktrace = stack?.split("\n") ?? []; + } else { + delete formattedError.extensions.stacktrace; + } + if (detailedMessage !== message) { + if (!formattedError.extensions.internalDetails) { + formattedError.extensions.internalDetails = {}; + } + formattedError.extensions.internalDetails.detailedMessage = + detailedMessage; + } + } else if (error instanceof DetailedError) { formattedError.extensions.code = error.code; if (error.details) { formattedError.extensions.details = error.details; diff --git a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts b/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts index b1391c0d..3033a240 100644 --- a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts @@ -6,7 +6,7 @@ import { PrismaClient, } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; -import Maybe, { just, nothing, of } from "true-myth/maybe"; +import Maybe, { just, nothing } from "true-myth/maybe"; import Result, { err, ok } from "true-myth/result"; import { Service } from "typedi"; @@ -76,20 +76,24 @@ export class FundraisingEntryRepository { param: FundraisingEntryUniqueParam ): Promise< Result< - Maybe< - FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry | null } - >, - SomePrismaError | BasicError + FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry }, + SomePrismaError | BasicError | NotFoundError > > { try { + const row = await this.prisma.fundraisingEntry.findUnique({ + where: param, + include: defaultInclude, + }); + if (!row?.dbFundsEntry) { + return err( + new NotFoundError({ what: "FundraisingEntry.dbFundsEntry" }) + ); + } return ok( - of( - await this.prisma.fundraisingEntry.findUnique({ - where: param, - include: defaultInclude, - }) - ) + row as typeof row & { + dbFundsEntry: NonNullable; + } ); } catch (error: unknown) { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); @@ -100,8 +104,8 @@ export class FundraisingEntryRepository { param: FundraisingEntryUniqueParam ): Promise< Result< - Maybe, - SomePrismaError | BasicError + readonly FundraisingAssignment[], + SomePrismaError | BasicError | NotFoundError > > { try { @@ -109,7 +113,10 @@ export class FundraisingEntryRepository { where: param, select: { assignments: true }, }); - return ok(of(entry?.assignments)); + if (!entry) { + return err(new NotFoundError({ what: "FundraisingEntry" })); + } + return ok(entry.assignments); } catch (error: unknown) { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } @@ -226,32 +233,18 @@ export class FundraisingEntryRepository { const entry = await this.findFundraisingEntryByUnique(entryParam); if (entry.isErr) { return err(entry.error); - } else if (entry.value.isNothing) { - return err(new NotFoundError({ what: "FundraisingEntry" })); } const assignments = await this.getFundraisingAssignmentsForEntry(entryParam); if (assignments.isErr) { return err(assignments.error); - } else if (assignments.value.isNothing) { - return err(new NotFoundError({ what: "FundraisingEntry" })); - } - - if (!entry.value.value.dbFundsEntry) { - return err( - new ActionDeniedError("Entry is not connected to a DBFunds entry") - ); } - const totalAssigned = assignments.value.value.reduce( + const totalAssigned = assignments.value.reduce( (acc, assignment) => acc.add(assignment.amount), new Prisma.Decimal(0) ); - if ( - entry.value.value.dbFundsEntry.amount.lessThan( - totalAssigned.add(amount) - ) - ) { + if (entry.value.dbFundsEntry.amount.lessThan(totalAssigned.add(amount))) { return err( new ActionDeniedError("Total assigned amount exceeds entry amount") ); @@ -314,8 +307,6 @@ export class FundraisingEntryRepository { }); if (assignments.isErr) { return err(assignments.error); - } else if (assignments.value.isNothing) { - return err(new NotFoundError({ what: "FundraisingEntry" })); } if (!assignment.parentEntry.dbFundsEntry) { @@ -324,7 +315,7 @@ export class FundraisingEntryRepository { ); } - const totalAssigned = assignments.value.value + const totalAssigned = assignments.value .filter((a) => a.id !== assignment.id) .reduce( (acc, assignment) => acc.add(assignment.amount), diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index e6748bc8..1c86682a 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -13,17 +13,19 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingEntryRepository.js"; + @Resolver(() => FundraisingAssignmentNode) @Service() export class FundraisingAssignmentResolver { - constructor(private readonly fundraisingRepository: FundraisingRepository) {} + constructor( + private readonly fundraisingEntryRepository: FundraisingEntryRepository + ) {} @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( @Arg("id") id: string - ): Promise { - // TODO - } + ): Promise {} @Mutation(() => FundraisingAssignmentNode) async createFundraisingAssignment( diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index a99cc090..055909e2 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -2,53 +2,48 @@ import { FundraisingAssignmentNode, FundraisingEntryNode, } from "@ukdanceblue/common"; -import { - Arg, - FieldResolver, - Mutation, - Query, - Resolver, - Root, -} from "type-graphql"; +import { Arg, FieldResolver, Query, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; +import { CatchableConcreteError } from "../lib/formatError.js"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingEntryRepository.js"; +import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; + @Resolver(() => FundraisingEntryNode) @Service() export class FundraisingEntryResolver { - constructor(private readonly fundraisingRepository: FundraisingRepository) {} + constructor( + private readonly fundraisingEntryRepository: FundraisingEntryRepository + ) {} @Query(() => FundraisingEntryNode) async fundraisingEntry(@Arg("id") id: string): Promise { - // TODO - } - - @Mutation(() => FundraisingEntryNode) - async createFundraisingEntry( - @Arg("input") input: CreateFundraisingEntryInput, - @Arg("teamId") teamId: string - ): Promise { - // TODO - } - - @Mutation(() => FundraisingEntryNode) - async updateFundraisingEntry( - @Arg("id") id: string, - @Arg("input") input: UpdateFundraisingEntryInput - ): Promise { - // TODO - } - - @Mutation(() => FundraisingEntryNode) - async deleteFundraisingEntry( - @Arg("id") id: string - ): Promise { - // TODO + const entry = + await this.fundraisingEntryRepository.findFundraisingEntryByUnique({ + uuid: id, + }); + if (entry.isErr) { + throw new CatchableConcreteError(entry.error); + } + return fundraisingEntryModelToNode(entry.value); } @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( @Root() entry: FundraisingEntryNode ): Promise { - // TODO + const assignments = + await this.fundraisingEntryRepository.getFundraisingAssignmentsForEntry({ + uuid: entry.id, + }); + if (assignments.isErr) { + throw new CatchableConcreteError(assignments.error); + } + return Promise.all( + assignments.value.map((assignment) => + fundraisingAssignmentModelToNode(assignment) + ) + ); } } From 801684fbe126b4789d0b819193d6f04793baf0be Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 6 Jun 2024 19:20:31 +0000 Subject: [PATCH 095/153] Add FundraisingAssignment and FundraisingEntry resolvers --- .../lib/graphql-client-admin/graphql.ts | 169 ++++++++++++++++ .../lib/graphql-client-public/graphql.ts | 169 ++++++++++++++++ packages/server/src/lib/graphqlSchema.ts | 4 + ...Repository.ts => FundraisingRepository.ts} | 163 ++++++++++++---- .../fundraisingEntryModelToNode.ts | 16 +- .../fundraisingEntryRepositoryUtils.ts | 35 +++- .../FundraisingAssignmentResolver.ts | 97 ++++++++-- .../src/resolvers/FundraisingEntryResolver.ts | 101 +++++++++- schema.graphql | 180 ++++++++++++++++++ 9 files changed, 849 insertions(+), 85 deletions(-) rename packages/server/src/repositories/fundraising/{FundraisingEntryRepository.ts => FundraisingRepository.ts} (68%) diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index be9a85a4..53bd4690 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -81,6 +81,10 @@ export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRespo readonly ok: Scalars['Boolean']['output']; }; +export type AssignEntryToPersonInput = { + readonly amount: Scalars['Float']['input']; +}; + export { AuthSource }; /** The identifier for a committee */ @@ -468,6 +472,105 @@ export type FeedNode = Node & { readonly updatedAt?: Maybe; }; +export type FundraisingAssignmentNode = Node & { + readonly __typename?: 'FundraisingAssignmentNode'; + readonly amount: Scalars['Float']['output']; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly person: PersonNode; + readonly updatedAt?: Maybe; +}; + +export type FundraisingEntryNode = Node & { + readonly __typename?: 'FundraisingEntryNode'; + readonly amount: Scalars['Float']['output']; + readonly assignments: ReadonlyArray; + readonly createdAt?: Maybe; + readonly donatedByText?: Maybe; + readonly donatedOn: Scalars['DateTimeISO']['output']; + readonly donatedToText?: Maybe; + readonly id: Scalars['ID']['output']; + readonly updatedAt?: Maybe; +}; + +export const FundraisingEntryResolverAllKeys = { + Amount: 'amount', + CreatedAt: 'createdAt', + DonatedBy: 'donatedBy', + DonatedOn: 'donatedOn', + DonatedTo: 'donatedTo', + UpdatedAt: 'updatedAt' +} as const; + +export type FundraisingEntryResolverAllKeys = typeof FundraisingEntryResolverAllKeys[keyof typeof FundraisingEntryResolverAllKeys]; +export const FundraisingEntryResolverDateFilterKeys = { + CreatedAt: 'createdAt', + DonatedOn: 'donatedOn', + UpdatedAt: 'updatedAt' +} as const; + +export type FundraisingEntryResolverDateFilterKeys = typeof FundraisingEntryResolverDateFilterKeys[keyof typeof FundraisingEntryResolverDateFilterKeys]; +export type FundraisingEntryResolverKeyedDateFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: NumericComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverDateFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['DateTimeISO']['input']; +}; + +export type FundraisingEntryResolverKeyedIsNullFilterItem = { + /** The field to filter on */ + readonly field: FundraisingEntryResolverAllKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; +}; + +export type FundraisingEntryResolverKeyedNumericFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: NumericComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverNumericFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['Float']['input']; +}; + +export type FundraisingEntryResolverKeyedOneOfFilterItem = { + /** The field to filter on */ + readonly field: FundraisingEntryResolverOneOfFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: ReadonlyArray; +}; + +export type FundraisingEntryResolverKeyedStringFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: StringComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverStringFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['String']['input']; +}; + +export const FundraisingEntryResolverNumericFilterKeys = { + Amount: 'amount' +} as const; + +export type FundraisingEntryResolverNumericFilterKeys = typeof FundraisingEntryResolverNumericFilterKeys[keyof typeof FundraisingEntryResolverNumericFilterKeys]; +export const FundraisingEntryResolverOneOfFilterKeys = { + TeamId: 'teamId' +} as const; + +export type FundraisingEntryResolverOneOfFilterKeys = typeof FundraisingEntryResolverOneOfFilterKeys[keyof typeof FundraisingEntryResolverOneOfFilterKeys]; +export const FundraisingEntryResolverStringFilterKeys = { + DonatedBy: 'donatedBy', + DonatedTo: 'donatedTo' +} as const; + +export type FundraisingEntryResolverStringFilterKeys = typeof FundraisingEntryResolverStringFilterKeys[keyof typeof FundraisingEntryResolverStringFilterKeys]; export type GetAllConfigurationsResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetAllConfigurationsResponse'; readonly data: ReadonlyArray; @@ -652,6 +755,18 @@ export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ readonly total: Scalars['NonNegativeInt']['output']; }; +export type ListFundraisingEntriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { + readonly __typename?: 'ListFundraisingEntriesResponse'; + readonly data: ReadonlyArray; + readonly ok: Scalars['Boolean']['output']; + /** The current page number (1-indexed) */ + readonly page: Scalars['PositiveInt']['output']; + /** The number of items per page */ + readonly pageSize: Scalars['NonNegativeInt']['output']; + /** The total number of items */ + readonly total: Scalars['NonNegativeInt']['output']; +}; + export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListImagesResponse'; readonly data: ReadonlyArray; @@ -844,6 +959,7 @@ export type Mutation = { readonly addExistingImageToEvent: AddEventImageResponse; readonly addMap: MarathonHourNode; readonly addPersonToTeam: GetMembershipResponse; + readonly assignEntryToPerson: FundraisingAssignmentNode; readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; @@ -860,6 +976,7 @@ export type Mutation = { readonly deleteDevice: DeleteDeviceResponse; readonly deleteEvent: DeleteEventResponse; readonly deleteFeedItem: Scalars['Boolean']['output']; + readonly deleteFundraisingAssignment: FundraisingAssignmentNode; readonly deleteImage: DeleteImageResponse; readonly deleteMarathon: Scalars['Void']['output']; readonly deleteMarathonHour: Scalars['Void']['output']; @@ -885,6 +1002,7 @@ export type Mutation = { readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; readonly stageNotification: StageNotificationResponse; + readonly updateFundraisingAssignment: FundraisingAssignmentNode; }; @@ -916,6 +1034,13 @@ export type MutationAddPersonToTeamArgs = { }; +export type MutationAssignEntryToPersonArgs = { + entryId: Scalars['String']['input']; + input: AssignEntryToPersonInput; + personId: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -999,6 +1124,11 @@ export type MutationDeleteFeedItemArgs = { }; +export type MutationDeleteFundraisingAssignmentArgs = { + id: Scalars['String']['input']; +}; + + export type MutationDeleteImageArgs = { uuid: Scalars['String']['input']; }; @@ -1133,6 +1263,12 @@ export type MutationStageNotificationArgs = { url?: InputMaybe; }; + +export type MutationUpdateFundraisingAssignmentArgs = { + id: Scalars['String']['input']; + input: UpdateFundraisingAssignmentInput; +}; + export type Node = { readonly id: Scalars['ID']['output']; }; @@ -1478,6 +1614,9 @@ export type Query = { readonly event: GetEventByUuidResponse; readonly events: ListEventsResponse; readonly feed: ReadonlyArray; + readonly fundraisingAssignment: FundraisingAssignmentNode; + readonly fundraisingEntries: ListFundraisingEntriesResponse; + readonly fundraisingEntry: FundraisingEntryNode; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; readonly listPeople: ListPeopleResponse; @@ -1555,6 +1694,32 @@ export type QueryFeedArgs = { }; +export type QueryFundraisingAssignmentArgs = { + id: Scalars['String']['input']; +}; + + +export type QueryFundraisingEntriesArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + + +export type QueryFundraisingEntryArgs = { + id: Scalars['String']['input']; +}; + + export type QueryImageArgs = { uuid: Scalars['String']['input']; }; @@ -1926,6 +2091,10 @@ export const TeamResolverStringFilterKeys = { export type TeamResolverStringFilterKeys = typeof TeamResolverStringFilterKeys[keyof typeof TeamResolverStringFilterKeys]; export { TeamType }; +export type UpdateFundraisingAssignmentInput = { + readonly amount: Scalars['Float']['input']; +}; + export type ImagePickerQueryVariables = Exact<{ stringFilters?: InputMaybe | ImageResolverKeyedStringFilterItem>; }>; diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 2f8aca18..915c0a87 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -81,6 +81,10 @@ export type AddEventImageResponse = AbstractGraphQlOkResponse & GraphQlBaseRespo readonly ok: Scalars['Boolean']['output']; }; +export type AssignEntryToPersonInput = { + readonly amount: Scalars['Float']['input']; +}; + export { AuthSource }; /** The identifier for a committee */ @@ -468,6 +472,105 @@ export type FeedNode = Node & { readonly updatedAt?: Maybe; }; +export type FundraisingAssignmentNode = Node & { + readonly __typename?: 'FundraisingAssignmentNode'; + readonly amount: Scalars['Float']['output']; + readonly createdAt?: Maybe; + readonly id: Scalars['ID']['output']; + readonly person: PersonNode; + readonly updatedAt?: Maybe; +}; + +export type FundraisingEntryNode = Node & { + readonly __typename?: 'FundraisingEntryNode'; + readonly amount: Scalars['Float']['output']; + readonly assignments: ReadonlyArray; + readonly createdAt?: Maybe; + readonly donatedByText?: Maybe; + readonly donatedOn: Scalars['DateTimeISO']['output']; + readonly donatedToText?: Maybe; + readonly id: Scalars['ID']['output']; + readonly updatedAt?: Maybe; +}; + +export const FundraisingEntryResolverAllKeys = { + Amount: 'amount', + CreatedAt: 'createdAt', + DonatedBy: 'donatedBy', + DonatedOn: 'donatedOn', + DonatedTo: 'donatedTo', + UpdatedAt: 'updatedAt' +} as const; + +export type FundraisingEntryResolverAllKeys = typeof FundraisingEntryResolverAllKeys[keyof typeof FundraisingEntryResolverAllKeys]; +export const FundraisingEntryResolverDateFilterKeys = { + CreatedAt: 'createdAt', + DonatedOn: 'donatedOn', + UpdatedAt: 'updatedAt' +} as const; + +export type FundraisingEntryResolverDateFilterKeys = typeof FundraisingEntryResolverDateFilterKeys[keyof typeof FundraisingEntryResolverDateFilterKeys]; +export type FundraisingEntryResolverKeyedDateFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: NumericComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverDateFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['DateTimeISO']['input']; +}; + +export type FundraisingEntryResolverKeyedIsNullFilterItem = { + /** The field to filter on */ + readonly field: FundraisingEntryResolverAllKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; +}; + +export type FundraisingEntryResolverKeyedNumericFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: NumericComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverNumericFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['Float']['input']; +}; + +export type FundraisingEntryResolverKeyedOneOfFilterItem = { + /** The field to filter on */ + readonly field: FundraisingEntryResolverOneOfFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: ReadonlyArray; +}; + +export type FundraisingEntryResolverKeyedStringFilterItem = { + /** The comparator to use for the filter */ + readonly comparison: StringComparator; + /** The field to filter on */ + readonly field: FundraisingEntryResolverStringFilterKeys; + /** Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. */ + readonly negate?: InputMaybe; + readonly value: Scalars['String']['input']; +}; + +export const FundraisingEntryResolverNumericFilterKeys = { + Amount: 'amount' +} as const; + +export type FundraisingEntryResolverNumericFilterKeys = typeof FundraisingEntryResolverNumericFilterKeys[keyof typeof FundraisingEntryResolverNumericFilterKeys]; +export const FundraisingEntryResolverOneOfFilterKeys = { + TeamId: 'teamId' +} as const; + +export type FundraisingEntryResolverOneOfFilterKeys = typeof FundraisingEntryResolverOneOfFilterKeys[keyof typeof FundraisingEntryResolverOneOfFilterKeys]; +export const FundraisingEntryResolverStringFilterKeys = { + DonatedBy: 'donatedBy', + DonatedTo: 'donatedTo' +} as const; + +export type FundraisingEntryResolverStringFilterKeys = typeof FundraisingEntryResolverStringFilterKeys[keyof typeof FundraisingEntryResolverStringFilterKeys]; export type GetAllConfigurationsResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetAllConfigurationsResponse'; readonly data: ReadonlyArray; @@ -652,6 +755,18 @@ export type ListEventsResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQ readonly total: Scalars['NonNegativeInt']['output']; }; +export type ListFundraisingEntriesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { + readonly __typename?: 'ListFundraisingEntriesResponse'; + readonly data: ReadonlyArray; + readonly ok: Scalars['Boolean']['output']; + /** The current page number (1-indexed) */ + readonly page: Scalars['PositiveInt']['output']; + /** The number of items per page */ + readonly pageSize: Scalars['NonNegativeInt']['output']; + /** The total number of items */ + readonly total: Scalars['NonNegativeInt']['output']; +}; + export type ListImagesResponse = AbstractGraphQlArrayOkResponse & AbstractGraphQlPaginatedResponse & GraphQlBaseResponse & { readonly __typename?: 'ListImagesResponse'; readonly data: ReadonlyArray; @@ -844,6 +959,7 @@ export type Mutation = { readonly addExistingImageToEvent: AddEventImageResponse; readonly addMap: MarathonHourNode; readonly addPersonToTeam: GetMembershipResponse; + readonly assignEntryToPerson: FundraisingAssignmentNode; readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; @@ -860,6 +976,7 @@ export type Mutation = { readonly deleteDevice: DeleteDeviceResponse; readonly deleteEvent: DeleteEventResponse; readonly deleteFeedItem: Scalars['Boolean']['output']; + readonly deleteFundraisingAssignment: FundraisingAssignmentNode; readonly deleteImage: DeleteImageResponse; readonly deleteMarathon: Scalars['Void']['output']; readonly deleteMarathonHour: Scalars['Void']['output']; @@ -885,6 +1002,7 @@ export type Mutation = { readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; readonly stageNotification: StageNotificationResponse; + readonly updateFundraisingAssignment: FundraisingAssignmentNode; }; @@ -916,6 +1034,13 @@ export type MutationAddPersonToTeamArgs = { }; +export type MutationAssignEntryToPersonArgs = { + entryId: Scalars['String']['input']; + input: AssignEntryToPersonInput; + personId: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -999,6 +1124,11 @@ export type MutationDeleteFeedItemArgs = { }; +export type MutationDeleteFundraisingAssignmentArgs = { + id: Scalars['String']['input']; +}; + + export type MutationDeleteImageArgs = { uuid: Scalars['String']['input']; }; @@ -1133,6 +1263,12 @@ export type MutationStageNotificationArgs = { url?: InputMaybe; }; + +export type MutationUpdateFundraisingAssignmentArgs = { + id: Scalars['String']['input']; + input: UpdateFundraisingAssignmentInput; +}; + export type Node = { readonly id: Scalars['ID']['output']; }; @@ -1478,6 +1614,9 @@ export type Query = { readonly event: GetEventByUuidResponse; readonly events: ListEventsResponse; readonly feed: ReadonlyArray; + readonly fundraisingAssignment: FundraisingAssignmentNode; + readonly fundraisingEntries: ListFundraisingEntriesResponse; + readonly fundraisingEntry: FundraisingEntryNode; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; readonly listPeople: ListPeopleResponse; @@ -1555,6 +1694,32 @@ export type QueryFeedArgs = { }; +export type QueryFundraisingAssignmentArgs = { + id: Scalars['String']['input']; +}; + + +export type QueryFundraisingEntriesArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + + +export type QueryFundraisingEntryArgs = { + id: Scalars['String']['input']; +}; + + export type QueryImageArgs = { uuid: Scalars['String']['input']; }; @@ -1926,6 +2091,10 @@ export const TeamResolverStringFilterKeys = { export type TeamResolverStringFilterKeys = typeof TeamResolverStringFilterKeys[keyof typeof TeamResolverStringFilterKeys]; export { TeamType }; +export type UpdateFundraisingAssignmentInput = { + readonly amount: Scalars['Float']['input']; +}; + export type ImageViewFragmentFragment = { readonly __typename?: 'ImageNode', readonly id: string, readonly url?: URL | string | null, readonly thumbHash?: string | null, readonly alt?: string | null, readonly width: number, readonly height: number, readonly mimeType: string } & { ' $fragmentName'?: 'ImageViewFragmentFragment' }; export type SimpleConfigFragment = { readonly __typename?: 'ConfigurationNode', readonly id: string, readonly key: string, readonly value: string } & { ' $fragmentName'?: 'SimpleConfigFragment' }; diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index c3dad45d..dc5efb55 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -8,6 +8,8 @@ import { ConfigurationResolver } from "../resolvers/ConfigurationResolver.js"; import { DeviceResolver } from "../resolvers/DeviceResolver.js"; import { EventResolver } from "../resolvers/EventResolver.js"; import { FeedResolver } from "../resolvers/FeedResolver.js"; +import { FundraisingAssignmentResolver } from "../resolvers/FundraisingAssignmentResolver.js"; +import { FundraisingEntryResolver } from "../resolvers/FundraisingEntryResolver.js"; import { ImageResolver } from "../resolvers/ImageResolver.js"; import { LoginStateResolver } from "../resolvers/LoginState.js"; import { MarathonHourResolver } from "../resolvers/MarathonHourResolver.js"; @@ -53,6 +55,8 @@ const resolvers = [ MarathonHourResolver, MarathonResolver, FeedResolver, + FundraisingAssignmentResolver, + FundraisingEntryResolver, ] as const; for (const service of resolvers) { diff --git a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts similarity index 68% rename from packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts rename to packages/server/src/repositories/fundraising/FundraisingRepository.ts index 3033a240..d84f9fba 100644 --- a/packages/server/src/repositories/fundraising/FundraisingEntryRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -2,6 +2,7 @@ import { DBFundsFundraisingEntry, FundraisingAssignment, FundraisingEntry, + Person, Prisma, PrismaClient, } from "@prisma/client"; @@ -38,13 +39,14 @@ type FundraisingEntryIsNullKey = (typeof fundraisingEntryIsNullKeys)[number]; const fundraisingEntryNumericKeys = ["amount"] as const; type FundraisingEntryNumericKey = (typeof fundraisingEntryNumericKeys)[number]; -const fundraisingEntryOneOfKeys = [] as const; +const fundraisingEntryOneOfKeys = ["teamId"] as const; type FundraisingEntryOneOfKey = (typeof fundraisingEntryOneOfKeys)[number]; const fundraisingEntryStringKeys = ["donatedTo", "donatedBy"] as const; type FundraisingEntryStringKey = (typeof fundraisingEntryStringKeys)[number]; export type FundraisingEntryOrderKeys = + | "teamId" | "donatedOn" | "amount" | "donatedTo" @@ -72,7 +74,7 @@ export type FundraisingAssignmentUniqueParam = SimpleUniqueParam; export class FundraisingEntryRepository { constructor(private readonly prisma: PrismaClient) {} - async findFundraisingEntryByUnique( + async findEntryByUnique( param: FundraisingEntryUniqueParam ): Promise< Result< @@ -100,7 +102,25 @@ export class FundraisingEntryRepository { } } - async getFundraisingAssignmentsForEntry( + async findAssignmentByUnique( + param: FundraisingAssignmentUniqueParam + ): Promise< + Result + > { + try { + const row = await this.prisma.fundraisingAssignment.findUnique({ + where: param, + }); + if (!row) { + return err(new NotFoundError({ what: "FundraisingAssignment" })); + } + return ok(row); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async getAssignmentsForEntry( param: FundraisingEntryUniqueParam ): Promise< Result< @@ -122,60 +142,109 @@ export class FundraisingEntryRepository { } } - async listFundraisingEntries({ - filters, - order, - skip, - take, - }: { - filters?: readonly FundraisingEntryFilters[] | undefined | null; - order?: - | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] - | undefined - | null; - skip?: number | undefined | null; - take?: number | undefined | null; - }): Promise< + async listEntries( + { + filters, + order, + skip, + take, + }: { + filters?: readonly FundraisingEntryFilters[] | undefined | null; + order?: + | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] + | undefined + | null; + skip?: number | undefined | null; + take?: number | undefined | null; + }, + limits: { + assignedToPerson?: SimpleUniqueParam | undefined | null; + forTeam?: SimpleUniqueParam | undefined | null; + } = {} + ): Promise< Result< readonly (FundraisingEntry & { - dbFundsEntry: DBFundsFundraisingEntry | null; + dbFundsEntry: DBFundsFundraisingEntry; })[], - SomePrismaError | BasicError + SomePrismaError | BasicError | ActionDeniedError > > { try { - const where = buildFundraisingEntryWhere(filters); - const orderBy = buildFundraisingEntryOrder(order); + const whereResult = buildFundraisingEntryWhere(filters); + const orderByResult = buildFundraisingEntryOrder(order); + if (whereResult.isErr) { + return err(whereResult.error); + } + if (orderByResult.isErr) { + return err(orderByResult.error); + } + const where = whereResult.value; + const orderBy = orderByResult.value; + + if (limits.assignedToPerson) { + where.assignments = { + ...where.assignments, + every: { + ...where.assignments?.every, + person: limits.assignedToPerson, + }, + }; + } + if (limits.forTeam) { + where.dbFundsEntry = { + ...where.dbFundsEntry, + // @ts-expect-error Don't know why this is causing an error, but I'm not going to worry about it + dbFundsTeam: { + // This 'satisfies' is to make sure that we don't accidentally ignore errors due to the ts-expect-error above + team: limits.forTeam satisfies Prisma.TeamWhereUniqueInput, + }, + }; + } + + const rows = await this.prisma.fundraisingEntry.findMany({ + include: defaultInclude, + where, + orderBy, + skip: skip ?? undefined, + take: take ?? undefined, + }); return ok( - await this.prisma.fundraisingEntry.findMany({ - include: defaultInclude, - where, - orderBy, - skip: skip ?? undefined, - take: take ?? undefined, - }) + rows.filter( + ( + row + ): row is typeof row & { + dbFundsEntry: NonNullable; + } => Boolean(row.dbFundsEntry) + ) ); } catch (error: unknown) { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } - async countFundraisingEntries({ + async countEntries({ filters, }: { filters?: readonly FundraisingEntryFilters[] | undefined | null; - }): Promise> { + }): Promise< + Result + > { try { const where = buildFundraisingEntryWhere(filters); + if (where.isErr) { + return err(where.error); + } - return ok(await this.prisma.fundraisingEntry.count({ where })); + return ok( + await this.prisma.fundraisingEntry.count({ where: where.value }) + ); } catch (error: unknown) { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } - async connectFundraisingEntry( + async connectEntry( dbFundsEntry: DBFundsFundraisingEntry ): Promise< Result @@ -198,7 +267,7 @@ export class FundraisingEntryRepository { } } - async deleteFundraisingEntry( + async deleteEntry( param: FundraisingEntryUniqueParam ): Promise, SomePrismaError | BasicError>> { try { @@ -219,7 +288,7 @@ export class FundraisingEntryRepository { } } - async addAssignmentToFundraisingEntry( + async addAssignmentToEntry( entryParam: FundraisingEntryUniqueParam, personParam: SimpleUniqueParam, { amount }: { amount: number } @@ -230,12 +299,11 @@ export class FundraisingEntryRepository { > > { try { - const entry = await this.findFundraisingEntryByUnique(entryParam); + const entry = await this.findEntryByUnique(entryParam); if (entry.isErr) { return err(entry.error); } - const assignments = - await this.getFundraisingAssignmentsForEntry(entryParam); + const assignments = await this.getAssignmentsForEntry(entryParam); if (assignments.isErr) { return err(assignments.error); } @@ -264,7 +332,7 @@ export class FundraisingEntryRepository { } } - async removeAssignmentFromFundraisingEntry( + async deleteAssignment( assignmentParam: FundraisingAssignmentUniqueParam ): Promise< Result @@ -302,7 +370,7 @@ export class FundraisingEntryRepository { if (!assignment) { return err(new NotFoundError({ what: "FundraisingEntry" })); } - const assignments = await this.getFundraisingAssignmentsForEntry({ + const assignments = await this.getAssignmentsForEntry({ id: assignment.parentEntry.id, }); if (assignments.isErr) { @@ -341,4 +409,21 @@ export class FundraisingEntryRepository { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } + + async getPersonForAssignment( + assignmentParam: FundraisingAssignmentUniqueParam + ): Promise> { + try { + const assignment = await this.prisma.fundraisingAssignment.findUnique({ + where: assignmentParam, + select: { person: true }, + }); + if (!assignment) { + return err(new NotFoundError({ what: "FundraisingAssignment" })); + } + return ok(assignment.person); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } } diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts b/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts index 08e64208..1858522f 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryModelToNode.ts @@ -2,19 +2,19 @@ import type { DBFundsFundraisingEntry, FundraisingEntry } from "@prisma/client"; import { FundraisingEntryNode } from "@ukdanceblue/common"; export function fundraisingEntryModelToNode( - marathonHourModel: FundraisingEntry & { + entryModel: FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry; } ): Promise { return Promise.resolve( FundraisingEntryNode.init({ - id: marathonHourModel.uuid, - amount: marathonHourModel.dbFundsEntry.amount.toNumber(), - donatedByText: marathonHourModel.dbFundsEntry.donatedBy, - donatedToText: marathonHourModel.dbFundsEntry.donatedTo, - donatedOn: marathonHourModel.dbFundsEntry.date, - createdAt: marathonHourModel.createdAt, - updatedAt: marathonHourModel.updatedAt, + id: entryModel.uuid, + amount: entryModel.dbFundsEntry.amount.toNumber(), + donatedByText: entryModel.dbFundsEntry.donatedBy, + donatedToText: entryModel.dbFundsEntry.donatedTo, + donatedOn: entryModel.dbFundsEntry.date, + createdAt: entryModel.createdAt, + updatedAt: entryModel.updatedAt, }) ); } diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index ae5da4a1..3668c15a 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -1,23 +1,27 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { Result } from "true-myth"; +import { err, ok } from "true-myth/result"; +import { ActionDeniedError } from "../../lib/error/control.js"; import { dateFilterToPrisma, numericFilterToPrisma, + oneOfFilterToPrisma, stringFilterToPrisma, } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { FundraisingEntryFilters, FundraisingEntryOrderKeys, -} from "./FundraisingEntryRepository.ts"; +} from "./FundraisingRepository.js"; export function buildFundraisingEntryOrder( order: | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] | null | undefined -) { +): Result { const orderBy: Prisma.FundraisingEntryOrderByWithRelationInput = {}; const dbFundsEntryOrderBy: Prisma.FundraisingEntryOrderByWithRelationInput["dbFundsEntry"] = {}; @@ -40,9 +44,14 @@ export function buildFundraisingEntryOrder( orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } + case "teamId": { + return err(new ActionDeniedError("Cannot sort by teamId")); + } default: { key satisfies never; - throw new Error(`Unsupported sort key: ${String(key)}`); + return err( + new ActionDeniedError(`Unsupported sort key: ${String(key)}`) + ); } } } @@ -51,12 +60,12 @@ export function buildFundraisingEntryOrder( orderBy["dbFundsEntry"] = dbFundsEntryOrderBy; } - return orderBy; + return ok(orderBy); } export function buildFundraisingEntryWhere( filters: readonly FundraisingEntryFilters[] | null | undefined -) { +): Result { const where: Prisma.FundraisingEntryWhereInput = {}; const dbFundsEntryWhere: Prisma.FundraisingEntryWhereInput["dbFundsEntry"] = {}; @@ -81,12 +90,18 @@ export function buildFundraisingEntryWhere( dbFundsEntryWhere[filter.field] = stringFilterToPrisma(filter); break; } + case "teamId": { + dbFundsEntryWhere.dbFundsTeam = { + team: { uuid: oneOfFilterToPrisma(filter) }, + }; + break; + } default: { filter satisfies never; - throw new Error( - `Unsupported filter key: ${String( - (filter as { field?: string } | undefined)?.field - )}` + return err( + new ActionDeniedError( + `Unsupported filter key: ${String((filter as { field?: string } | undefined)?.field)}` + ) ); } } @@ -96,5 +111,5 @@ export function buildFundraisingEntryWhere( where["dbFundsEntry"] = dbFundsEntryWhere; } - return where; + return ok(where); } diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 1c86682a..0f5925ce 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -1,11 +1,9 @@ -import { - FundraisingAssignmentNode, - FundraisingEntryNode, - PersonNode, -} from "@ukdanceblue/common"; +import { FundraisingAssignmentNode, PersonNode } from "@ukdanceblue/common"; import { Arg, + Field, FieldResolver, + InputType, Mutation, Query, Resolver, @@ -13,53 +11,110 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingEntryRepository.js"; +import { CatchableConcreteError } from "../lib/formatError.js"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; +import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { PersonRepository } from "../repositories/person/PersonRepository.js"; +import { personModelToResource } from "../repositories/person/personModelToResource.js"; + +@InputType() +class AssignEntryToPersonInput { + @Field() + amount!: number; +} + +@InputType() +class UpdateFundraisingAssignmentInput { + @Field() + amount!: number; +} @Resolver(() => FundraisingAssignmentNode) @Service() export class FundraisingAssignmentResolver { constructor( - private readonly fundraisingEntryRepository: FundraisingEntryRepository + private readonly fundraisingEntryRepository: FundraisingEntryRepository, + private readonly personRepository: PersonRepository ) {} @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( @Arg("id") id: string - ): Promise {} + ): Promise { + const assignment = + await this.fundraisingEntryRepository.findAssignmentByUnique({ + uuid: id, + }); + + if (assignment.isErr) { + throw new CatchableConcreteError(assignment.error); + } + + return fundraisingAssignmentModelToNode(assignment.value); + } @Mutation(() => FundraisingAssignmentNode) - async createFundraisingAssignment( - @Arg("input") input: CreateFundraisingAssignmentInput + async assignEntryToPerson( + @Arg("entryId") entryId: string, + @Arg("personId") personId: string, + @Arg("input") { amount }: AssignEntryToPersonInput ): Promise { - // TODO + const assignment = + await this.fundraisingEntryRepository.addAssignmentToEntry( + { uuid: entryId }, + { uuid: personId }, + { amount } + ); + + if (assignment.isErr) { + throw new CatchableConcreteError(assignment.error); + } + + return fundraisingAssignmentModelToNode(assignment.value); } @Mutation(() => FundraisingAssignmentNode) async updateFundraisingAssignment( @Arg("id") id: string, - @Arg("input") input: UpdateFundraisingAssignmentInput + @Arg("input") { amount }: UpdateFundraisingAssignmentInput ): Promise { - // TODO + const assignment = await this.fundraisingEntryRepository.updateAssignment( + { uuid: id }, + { amount } + ); + + if (assignment.isErr) { + throw new CatchableConcreteError(assignment.error); + } + + return fundraisingAssignmentModelToNode(assignment.value); } @Mutation(() => FundraisingAssignmentNode) async deleteFundraisingAssignment( @Arg("id") id: string ): Promise { - // TODO - } + const assignment = await this.fundraisingEntryRepository.deleteAssignment({ + uuid: id, + }); - @FieldResolver(() => FundraisingEntryNode) - async entry( - @Root() assignment: FundraisingAssignmentNode - ): Promise { - // TODO + if (assignment.isErr) { + throw new CatchableConcreteError(assignment.error); + } + + return fundraisingAssignmentModelToNode(assignment.value); } @FieldResolver(() => PersonNode) async person( @Root() assignment: FundraisingAssignmentNode ): Promise { - // TODO + const person = await this.fundraisingEntryRepository.getPersonForAssignment( + { uuid: assignment.id } + ); + if (person.isErr) { + throw new CatchableConcreteError(person.error); + } + return personModelToResource(person.value, this.personRepository); } } diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 055909e2..3e9d488e 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -1,15 +1,66 @@ import { + FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, + SortDirection, } from "@ukdanceblue/common"; -import { Arg, FieldResolver, Query, Resolver, Root } from "type-graphql"; +import { + Arg, + Args, + ArgsType, + Field, + FieldResolver, + ObjectType, + Query, + Resolver, + Root, +} from "type-graphql"; import { Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingEntryRepository.js"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; + +@ArgsType() +class ListFundraisingEntriesArgs extends FilteredListQueryArgs< + | "donatedOn" + | "amount" + | "donatedTo" + | "donatedBy" + | "teamId" + | "createdAt" + | "updatedAt", + "donatedTo" | "donatedBy", + "teamId", + "amount", + "donatedOn" | "createdAt" | "updatedAt", + never +>("FundraisingEntryResolver", { + all: [ + "donatedOn", + "amount", + "donatedTo", + "donatedBy", + "createdAt", + "updatedAt", + ], + string: ["donatedTo", "donatedBy"], + numeric: ["amount"], + oneOf: ["teamId"], + date: ["donatedOn", "createdAt", "updatedAt"], +}) {} + +@ObjectType("ListFundraisingEntriesResponse", { + implements: AbstractGraphQLPaginatedResponse, +}) +class ListFundraisingEntriesResponse extends AbstractGraphQLPaginatedResponse { + @Field(() => [FundraisingEntryNode]) + data!: FundraisingEntryNode[]; +} + @Resolver(() => FundraisingEntryNode) @Service() export class FundraisingEntryResolver { @@ -19,22 +70,58 @@ export class FundraisingEntryResolver { @Query(() => FundraisingEntryNode) async fundraisingEntry(@Arg("id") id: string): Promise { - const entry = - await this.fundraisingEntryRepository.findFundraisingEntryByUnique({ - uuid: id, - }); + const entry = await this.fundraisingEntryRepository.findEntryByUnique({ + uuid: id, + }); if (entry.isErr) { throw new CatchableConcreteError(entry.error); } return fundraisingEntryModelToNode(entry.value); } + @Query(() => ListFundraisingEntriesResponse) + async fundraisingEntries( + @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs + ): Promise { + const entries = await this.fundraisingEntryRepository.listEntries({ + filters: args.filters, + order: + args.sortBy?.map((key, i) => [ + key, + args.sortDirection?.[i] ?? SortDirection.desc, + ]) ?? [], + skip: + args.page != null && args.pageSize != null + ? (args.page - 1) * args.pageSize + : null, + take: args.pageSize, + }); + const count = await this.fundraisingEntryRepository.countEntries({ + filters: args.filters, + }); + + if (entries.isErr) { + throw new CatchableConcreteError(entries.error); + } + if (count.isErr) { + throw new CatchableConcreteError(count.error); + } + + return ListFundraisingEntriesResponse.newPaginated({ + data: await Promise.all( + entries.value.map((model) => fundraisingEntryModelToNode(model)) + ), + total: count.value, + page: args.page, + pageSize: args.pageSize, + }); + } @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( @Root() entry: FundraisingEntryNode ): Promise { const assignments = - await this.fundraisingEntryRepository.getFundraisingAssignmentsForEntry({ + await this.fundraisingEntryRepository.getAssignmentsForEntry({ uuid: entry.id, }); if (assignments.isErr) { diff --git a/schema.graphql b/schema.graphql index 95c71421..948817c0 100644 --- a/schema.graphql +++ b/schema.graphql @@ -48,6 +48,10 @@ type AddEventImageResponse implements AbstractGraphQLOkResponse & GraphQLBaseRes ok: Boolean! } +input AssignEntryToPersonInput { + amount: Float! +} + """The source of authentication""" enum AuthSource { Anonymous @@ -456,6 +460,116 @@ type FeedNode implements Node { updatedAt: DateTimeISO } +type FundraisingAssignmentNode implements Node { + amount: Float! + createdAt: DateTimeISO + id: ID! + person: PersonNode! + updatedAt: DateTimeISO +} + +type FundraisingEntryNode implements Node { + amount: Float! + assignments: [FundraisingAssignmentNode!]! + createdAt: DateTimeISO + donatedByText: String + donatedOn: DateTimeISO! + donatedToText: String + id: ID! + updatedAt: DateTimeISO +} + +enum FundraisingEntryResolverAllKeys { + amount + createdAt + donatedBy + donatedOn + donatedTo + updatedAt +} + +enum FundraisingEntryResolverDateFilterKeys { + createdAt + donatedOn + updatedAt +} + +input FundraisingEntryResolverKeyedDateFilterItem { + """The comparator to use for the filter""" + comparison: NumericComparator! + + """The field to filter on""" + field: FundraisingEntryResolverDateFilterKeys! + + """ + Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. + """ + negate: Boolean = false + value: DateTimeISO! +} + +input FundraisingEntryResolverKeyedIsNullFilterItem { + """The field to filter on""" + field: FundraisingEntryResolverAllKeys! + + """ + Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. + """ + negate: Boolean = false +} + +input FundraisingEntryResolverKeyedNumericFilterItem { + """The comparator to use for the filter""" + comparison: NumericComparator! + + """The field to filter on""" + field: FundraisingEntryResolverNumericFilterKeys! + + """ + Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. + """ + negate: Boolean = false + value: Float! +} + +input FundraisingEntryResolverKeyedOneOfFilterItem { + """The field to filter on""" + field: FundraisingEntryResolverOneOfFilterKeys! + + """ + Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. + """ + negate: Boolean = false + value: [String!]! +} + +input FundraisingEntryResolverKeyedStringFilterItem { + """The comparator to use for the filter""" + comparison: StringComparator! + + """The field to filter on""" + field: FundraisingEntryResolverStringFilterKeys! + + """ + Should the comparator be negated? WARNING: This will throw if used on a comparator that does not support negation. + """ + negate: Boolean = false + value: String! +} + +enum FundraisingEntryResolverNumericFilterKeys { + amount +} + +enum FundraisingEntryResolverOneOfFilterKeys { + teamId +} + +enum FundraisingEntryResolverStringFilterKeys { + donatedBy + donatedTo +} + type GetAllConfigurationsResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { data: [ConfigurationNode!]! ok: Boolean! @@ -646,6 +760,20 @@ type ListEventsResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap total: NonNegativeInt! } +type ListFundraisingEntriesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { + data: [FundraisingEntryNode!]! + ok: Boolean! + + """The current page number (1-indexed)""" + page: PositiveInt! + + """The number of items per page""" + pageSize: NonNegativeInt! + + """The total number of items""" + total: NonNegativeInt! +} + type ListImagesResponse implements AbstractGraphQLArrayOkResponse & AbstractGraphQLPaginatedResponse & GraphQLBaseResponse { data: [ImageNode!]! ok: Boolean! @@ -858,6 +986,7 @@ type Mutation { addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! addMap(imageUuid: String!, uuid: String!): MarathonHourNode! addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! + assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! createConfiguration(input: CreateConfigurationInput!): CreateConfigurationResponse! createConfigurations(input: [CreateConfigurationInput!]!): CreateConfigurationResponse! @@ -874,6 +1003,7 @@ type Mutation { deleteDevice(uuid: String!): DeleteDeviceResponse! deleteEvent(uuid: String!): DeleteEventResponse! deleteFeedItem(feedItemUuid: String!): Boolean! + deleteFundraisingAssignment(id: String!): FundraisingAssignmentNode! deleteImage(uuid: String!): DeleteImageResponse! deleteMarathon(uuid: String!): Void! deleteMarathonHour(uuid: String!): Void! @@ -906,6 +1036,7 @@ type Mutation { setPointOpportunity(input: SetPointOpportunityInput!, uuid: String!): SinglePointOpportunityResponse! setTeam(input: SetTeamInput!, uuid: String!): SingleTeamResponse! stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! + updateFundraisingAssignment(id: String!, input: UpdateFundraisingAssignmentInput!): FundraisingAssignmentNode! } interface Node { @@ -1389,6 +1520,51 @@ type Query { stringFilters: [EventResolverKeyedStringFilterItem!] ): ListEventsResponse! feed(limit: Int = 10): [FeedNode!]! + fundraisingAssignment(id: String!): FundraisingAssignmentNode! + fundraisingEntries( + """The boolean filters to apply to the query""" + booleanFilters: Void + + """The date filters to apply to the query""" + dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] + + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + + """The is-null filters to apply to the query""" + isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] + + """The numeric filters to apply to the query""" + numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] + + """The one-of filters to apply to the query""" + oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] + + """The page number to return, defaults to 1""" + page: Int + + """The number of items to return per page, defaults to 10""" + pageSize: Int + + """ + Whether to send all results in a single page, defaults to false (should generally be avoided) + """ + sendAll: Boolean + + """ + The fields to sort by, in order of priority. If unspecified, the sort order is undefined + """ + sortBy: [String!] + + """ + The direction to sort, if not specified will default to ascending, the order of the values in this array should match the order of the values in the sortBy array, if only one value is specified it will be used for all sortBy values, otherwise the lengths must match + """ + sortDirection: [SortDirection!] + + """The string filters to apply to the query""" + stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] + ): ListFundraisingEntriesResponse! + fundraisingEntry(id: String!): FundraisingEntryNode! image(uuid: String!): GetImageByUuidResponse! images( """The boolean filters to apply to the query""" @@ -1965,5 +2141,9 @@ A field whose value conforms to the standard URL format as specified in RFC3986: """ scalar URL +input UpdateFundraisingAssignmentInput { + amount: Float! +} + """Represents NULL values""" scalar Void \ No newline at end of file From 1a3736e77ff9dcb33fea930a4ed75c715f3d1fc2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 6 Jun 2024 19:36:14 +0000 Subject: [PATCH 096/153] Update checkAuthorization function to support asynchronous custom authorization checks --- .../lib/api/resources/authorization.test.ts | 167 ++++++++++-------- .../common/lib/authorization/accessControl.ts | 20 ++- .../common/lib/authorization/role.test.ts | 2 + 3 files changed, 104 insertions(+), 85 deletions(-) diff --git a/packages/common/lib/api/resources/authorization.test.ts b/packages/common/lib/api/resources/authorization.test.ts index e865effa..360c0275 100644 --- a/packages/common/lib/api/resources/authorization.test.ts +++ b/packages/common/lib/api/resources/authorization.test.ts @@ -108,89 +108,96 @@ const none: Authorization = { committees: [], }; describe("checkAuthorization", () => { - it("should return true when the user's access level matches the required access level", () => { - expect( + it("should return true when the user's access level matches the required access level", async () => { + expect.hasAssertions(); + + await expect( checkAuthorization({ accessLevel: AccessLevel.Admin }, techChair) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization({ accessLevel: AccessLevel.Admin }, techCoordinator) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization({ accessLevel: AccessLevel.Admin }, techMember) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.CommitteeChairOrCoordinator }, overallChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.CommitteeChairOrCoordinator }, dancerRelationsChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.CommitteeChairOrCoordinator }, dancerRelationsCoordinator ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.Committee }, dancerRelationsMember ) - ).toBe(true); - expect(checkAuthorization({ accessLevel: AccessLevel.UKY }, member)).toBe( - true - ); - expect( + ).resolves.toBe(true); + await expect( + checkAuthorization({ accessLevel: AccessLevel.UKY }, member) + ).resolves.toBe(true); + await expect( checkAuthorization({ accessLevel: AccessLevel.Public }, publicAuth) - ).toBe(true); - expect(checkAuthorization({ accessLevel: AccessLevel.None }, none)).toBe( - true - ); + ).resolves.toBe(true); + await expect( + checkAuthorization({ accessLevel: AccessLevel.None }, none) + ).resolves.toBe(true); }); - it("should return true when the user's access level is higher than the required access level", () => { - expect( + // TODO: Make the rest of these async + + it("should return true when the user's access level is higher than the required access level", async () => { + expect.assertions(3); + await expect( checkAuthorization({ accessLevel: AccessLevel.Committee }, techChair) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.Committee }, techCoordinator ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization({ accessLevel: AccessLevel.Committee }, techMember) - ).toBe(true); + ).resolves.toBe(true); }); - it("should return false when the user's access level is lower than the required access level", () => { - expect( + it("should return false when the user's access level is lower than the required access level", async () => { + expect.assertions(4); + await expect( checkAuthorization( { accessLevel: AccessLevel.CommitteeChairOrCoordinator }, dancerRelationsMember ) - ).toBe(false); - expect( + ).resolves.toBe(false); + await expect( checkAuthorization({ accessLevel: AccessLevel.UKY }, publicAuth) - ).toBe(false); - expect(checkAuthorization({ accessLevel: AccessLevel.Public }, none)).toBe( - false - ); - expect( + ).resolves.toBe(false); + await expect( + checkAuthorization({ accessLevel: AccessLevel.Public }, none) + ).resolves.toBe(false); + await expect( checkAuthorization( { accessLevel: AccessLevel.CommitteeChairOrCoordinator }, none ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with a custom check function", () => { - expect( + it("should work with a custom check function", async () => { + expect.assertions(2); + await expect( checkAuthorization( { custom() { @@ -199,8 +206,8 @@ describe("checkAuthorization", () => { }, { accessLevel: AccessLevel.None, dbRole: DbRole.None, committees: [] } ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { custom() { @@ -209,30 +216,32 @@ describe("checkAuthorization", () => { }, { accessLevel: AccessLevel.None, dbRole: DbRole.None, committees: [] } ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with committeeIdentifier matching", () => { - expect( + it("should work with committeeIdentifier matching", async () => { + expect.assertions(2); + await expect( checkAuthorization( { committeeIdentifier: CommitteeIdentifier.techCommittee, }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { committeeIdentifier: CommitteeIdentifier.techCommittee, }, none ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with committeeIdentifiers matching", () => { - expect( + it("should work with committeeIdentifiers matching", async () => { + expect.assertions(2); + await expect( checkAuthorization( { committeeIdentifiers: [ @@ -242,8 +251,8 @@ describe("checkAuthorization", () => { }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { committeeIdentifiers: [ @@ -253,68 +262,72 @@ describe("checkAuthorization", () => { }, none ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with exact dbRole matching", () => { - expect( + it("should work with exact dbRole matching", async () => { + expect.assertions(2); + await expect( checkAuthorization( { dbRole: DbRole.Committee, }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { dbRole: DbRole.Committee, }, none ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with minimum dbRole matching", () => { - expect( + it("should work with minimum dbRole matching", async () => { + expect.assertions(1); + await expect( checkAuthorization( { minDbRole: DbRole.Committee, }, techChair ) - ).toBe(true); + ).resolves.toBe(true); }); - it("should work with minimum committeeRole matching", () => { - expect( + it("should work with minimum committeeRole matching", async () => { + expect.assertions(3); + await expect( checkAuthorization( { minCommitteeRole: CommitteeRole.Chair, }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { minCommitteeRole: CommitteeRole.Coordinator, }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { minCommitteeRole: CommitteeRole.Coordinator, }, none ) - ).toBe(false); + ).resolves.toBe(false); }); - it("should work with all of the above", () => { - expect( + it("should work with all of the above", async () => { + expect.assertions(3); + await expect( checkAuthorization( { accessLevel: AccessLevel.Admin, @@ -323,8 +336,8 @@ describe("checkAuthorization", () => { }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.Admin, @@ -334,8 +347,8 @@ describe("checkAuthorization", () => { }, techChair ) - ).toBe(true); - expect( + ).resolves.toBe(true); + await expect( checkAuthorization( { accessLevel: AccessLevel.Admin, @@ -344,6 +357,6 @@ describe("checkAuthorization", () => { }, none ) - ).toBe(false); + ).resolves.toBe(false); }); }); diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 25e83691..65292331 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -60,7 +60,7 @@ export interface AuthorizationRule { * * Should usually be avoided, but can be used for more complex authorization rules */ - custom?: (authorization: Authorization) => boolean; + custom?: (authorization: Authorization) => boolean | Promise; } export function prettyPrintAuthorizationRule(rule: AuthorizationRule): string { @@ -94,7 +94,7 @@ export function prettyPrintAuthorizationRule(rule: AuthorizationRule): string { return parts.join(", "); } -export function checkAuthorization( +export async function checkAuthorization( { accessLevel, committeeIdentifier, @@ -190,8 +190,7 @@ export function checkAuthorization( // Custom auth checker if (custom != null) { - matches &&= custom(authorization); - console.log(`Custom auth check: ${matches}`); + matches &&= await custom(authorization); } return matches; } @@ -245,7 +244,7 @@ export function AccessControl< >( ...params: AccessControlParam[] ): MethodDecorator & PropertyDecorator { - const middleware: MiddlewareFn = ( + const middleware: MiddlewareFn = async ( resolverData, next ) => { @@ -269,9 +268,14 @@ export function AccessControl< "Resource has no allowed authorization rules." ); } - const matches = rule.authRules.some((rule) => - checkAuthorization(rule, authorization) - ); + let matches = false; + for (const authRule of rule.authRules) { + // eslint-disable-next-line no-await-in-loop + matches = await checkAuthorization(authRule, authorization); + if (matches) { + break; + } + } if (!matches) { continue; } diff --git a/packages/common/lib/authorization/role.test.ts b/packages/common/lib/authorization/role.test.ts index 0efe187d..0ea006e3 100644 --- a/packages/common/lib/authorization/role.test.ts +++ b/packages/common/lib/authorization/role.test.ts @@ -9,6 +9,8 @@ import { import { roleToAccessLevel } from "./role.js"; +// TODO test the committee hierarchy system (i.e. overall and vice roles vs other committees) + describe("roleToAccessLevel", () => { it("returns the correct access level for a given role normally", () => { const chairRole = { From 05f761a6f8263292aef1a0765ecd94f2224dea4c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 6 Jun 2024 19:57:09 +0000 Subject: [PATCH 097/153] More work on implementing fundraising tracking --- .../common/lib/authorization/accessControl.ts | 38 ++++++++--- .../fundraising/DBFundsRepository.ts | 28 +++++++- .../src/resolvers/FundraisingEntryResolver.ts | 67 ++++++++++++++++++- 3 files changed, 118 insertions(+), 15 deletions(-) diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 65292331..75a6ace0 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -209,11 +209,13 @@ interface ExtractorData { * 1. The user's access level is greater than or equal to the access level specified (AccessLevel.None by default) * 2. The user's role matches one of the specified authorization rules * 3. The resolver arguments match ALL of the specified argument matchers + * 4. The root object matches ALL of the specified root matchers + * 5. The custom authorization rule returns true */ -export interface AccessControlParam< - RootType extends Record = Record, -> { - authRules?: readonly AuthorizationRule[]; +export interface AccessControlParam { + authRules?: + | readonly AuthorizationRule[] + | ((root: RootType) => readonly AuthorizationRule[]); accessLevel?: AccessLevel; argumentMatch?: { argument: string | ((args: ArgsDictionary) => Primitive | Primitive[]); @@ -223,6 +225,15 @@ export interface AccessControlParam< root: string | ((root: RootType) => Primitive | Primitive[]); extractor: (param: ExtractorData) => Primitive | Primitive[]; }[]; + /** + * Custom authorization rule + * + * Should usually be avoided, but can be used for more complex authorization rules + */ + custom?: ( + root: RootType, + authorization: ExtractorData + ) => boolean | Promise; } export interface SimpleTeamMembership { @@ -239,9 +250,7 @@ export interface AuthorizationContext { authorization: Authorization; } -export function AccessControl< - RootType extends Record = Record, ->( +export function AccessControl( ...params: AccessControlParam[] ): MethodDecorator & PropertyDecorator { const middleware: MiddlewareFn = async ( @@ -262,14 +271,18 @@ export function AccessControl< } if (rule.authRules != null) { - if (rule.authRules.length === 0) { + const authRules = + typeof rule.authRules === "function" + ? rule.authRules(root) + : rule.authRules; + if (authRules.length === 0) { throw new DetailedError( ErrorCode.InternalFailure, "Resource has no allowed authorization rules." ); } let matches = false; - for (const authRule of rule.authRules) { + for (const authRule of authRules) { // eslint-disable-next-line no-await-in-loop matches = await checkAuthorization(authRule, authorization); if (matches) { @@ -345,6 +358,13 @@ export function AccessControl< } } + if (rule.custom != null) { + // eslint-disable-next-line no-await-in-loop + if (!(await rule.custom(root, context))) { + continue; + } + } + ok = true; break; } diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 75f18e78..d09d528e 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,11 +1,16 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient, Team } from "@prisma/client"; import type { DateTime } from "luxon"; import { Maybe, Result } from "true-myth"; +import { err, ok } from "true-myth/result"; import { Service } from "typedi"; import { NotFoundError } from "../../lib/error/direct.js"; -import { toBasicError } from "../../lib/error/error.js"; -import { PrismaError, toPrismaError } from "../../lib/error/prisma.js"; +import { BasicError, toBasicError } from "../../lib/error/error.js"; +import { + PrismaError, + SomePrismaError, + toPrismaError, +} from "../../lib/error/prisma.js"; import { type JsResult } from "../../lib/error/result.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; @@ -93,4 +98,21 @@ export class DBFundsRepository { ); } } + + async getTeamForDbFundsTeam(dbFundsTeamParam: { + id: number; + }): Promise> { + try { + const team = await this.prisma.dBFundsTeam.findUnique({ + where: dbFundsTeamParam, + include: { team: true }, + }); + if (!team?.team) { + return err(new NotFoundError({ what: "Team" })); + } + return ok(team.team); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } } diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 3e9d488e..8078f944 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -1,7 +1,12 @@ +import { CommitteeRole } from "@prisma/client"; import { + AccessControl, + AccessControlParam, + CommitteeIdentifier, FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, + MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; import { @@ -15,9 +20,10 @@ import { Resolver, Root, } from "type-graphql"; -import { Service } from "typedi"; +import { Container, Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; +import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; @@ -25,7 +31,7 @@ import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundrai import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ArgsType() -class ListFundraisingEntriesArgs extends FilteredListQueryArgs< +export class ListFundraisingEntriesArgs extends FilteredListQueryArgs< | "donatedOn" | "amount" | "donatedTo" @@ -56,11 +62,20 @@ class ListFundraisingEntriesArgs extends FilteredListQueryArgs< @ObjectType("ListFundraisingEntriesResponse", { implements: AbstractGraphQLPaginatedResponse, }) -class ListFundraisingEntriesResponse extends AbstractGraphQLPaginatedResponse { +export class ListFundraisingEntriesResponse extends AbstractGraphQLPaginatedResponse { @Field(() => [FundraisingEntryNode]) data!: FundraisingEntryNode[]; } +const fundraisingAccess: AccessControlParam = { + authRules: [ + { + minCommitteeRole: CommitteeRole.Coordinator, + committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], + }, + ], +}; + @Resolver(() => FundraisingEntryNode) @Service() export class FundraisingEntryResolver { @@ -68,6 +83,7 @@ export class FundraisingEntryResolver { private readonly fundraisingEntryRepository: FundraisingEntryRepository ) {} + @AccessControl(fundraisingAccess) @Query(() => FundraisingEntryNode) async fundraisingEntry(@Arg("id") id: string): Promise { const entry = await this.fundraisingEntryRepository.findEntryByUnique({ @@ -79,6 +95,7 @@ export class FundraisingEntryResolver { return fundraisingEntryModelToNode(entry.value); } + @AccessControl(fundraisingAccess) @Query(() => ListFundraisingEntriesResponse) async fundraisingEntries( @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs @@ -116,6 +133,50 @@ export class FundraisingEntryResolver { pageSize: args.pageSize, }); } + + @AccessControl( + // You can view assignments for an entry if you are: + // 1. A fundraising coordinator or chair + fundraisingAccess, + // 2. The captain of the team the entry is associated with + { + custom: async ( + { id }, + { teamMemberships, userData: { userId } } + ): Promise => { + if (userId == null) { + return false; + } + const captainOf = teamMemberships + .filter( + (membership) => + membership.position === MembershipPositionType.Captain + ) + .map((membership) => membership.teamId); + if (captainOf.length === 0) { + return false; + } + + const fundraisingEntryRepository = Container.get( + FundraisingEntryRepository + ); + const entry = await fundraisingEntryRepository.findEntryByUnique({ + uuid: id, + }); + if (entry.isErr) { + return false; + } + const dbFundsRepository = Container.get(DBFundsRepository); + const team = await dbFundsRepository.getTeamForDbFundsTeam({ + id: entry.value.dbFundsEntry.dbFundsTeamId, + }); + if (team.isErr) { + return false; + } + return captainOf.includes(team.value.uuid); + }, + } + ) @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( @Root() entry: FundraisingEntryNode From 0682b7f56eb4c98fb55d53b5529ea172ee257c97 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 6 Jun 2024 20:10:25 +0000 Subject: [PATCH 098/153] Add an entry point for fundraising to teams --- .../lib/graphql-client-admin/graphql.ts | 17 ++++ .../lib/graphql-client-public/graphql.ts | 17 ++++ .../FundraisingAssignmentResolver.ts | 24 ++++- .../src/resolvers/FundraisingEntryResolver.ts | 90 +++++++++---------- packages/server/src/resolvers/TeamResolver.ts | 74 ++++++++++++++- schema.graphql | 43 +++++++++ 6 files changed, 218 insertions(+), 47 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 53bd4690..9aeed0a2 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -2033,6 +2033,7 @@ export type TeamNode = Node & { /** @deprecated Just query the members field and filter by role */ readonly captains: ReadonlyArray; readonly createdAt?: Maybe; + readonly fundraisingEntries: ListFundraisingEntriesResponse; readonly id: Scalars['ID']['output']; readonly legacyStatus: TeamLegacyStatus; readonly marathon: MarathonNode; @@ -2044,6 +2045,22 @@ export type TeamNode = Node & { readonly updatedAt?: Maybe; }; + +export type TeamNodeFundraisingEntriesArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', MarathonYear: 'marathonYear', diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 915c0a87..df3a2468 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -2033,6 +2033,7 @@ export type TeamNode = Node & { /** @deprecated Just query the members field and filter by role */ readonly captains: ReadonlyArray; readonly createdAt?: Maybe; + readonly fundraisingEntries: ListFundraisingEntriesResponse; readonly id: Scalars['ID']['output']; readonly legacyStatus: TeamLegacyStatus; readonly marathon: MarathonNode; @@ -2044,6 +2045,22 @@ export type TeamNode = Node & { readonly updatedAt?: Maybe; }; + +export type TeamNodeFundraisingEntriesArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', MarathonYear: 'marathonYear', diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 0f5925ce..9432ec8c 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -1,4 +1,11 @@ -import { FundraisingAssignmentNode, PersonNode } from "@ukdanceblue/common"; +import { + AccessControl, + AccessControlParam, + CommitteeIdentifier, + CommitteeRole, + FundraisingAssignmentNode, + PersonNode, +} from "@ukdanceblue/common"; import { Arg, Field, @@ -29,6 +36,15 @@ class UpdateFundraisingAssignmentInput { amount!: number; } +const fundraisingAccess: AccessControlParam = { + authRules: [ + { + minCommitteeRole: CommitteeRole.Coordinator, + committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], + }, + ], +}; + @Resolver(() => FundraisingAssignmentNode) @Service() export class FundraisingAssignmentResolver { @@ -37,6 +53,7 @@ export class FundraisingAssignmentResolver { private readonly personRepository: PersonRepository ) {} + @AccessControl(fundraisingAccess) @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( @Arg("id") id: string @@ -53,6 +70,7 @@ export class FundraisingAssignmentResolver { return fundraisingAssignmentModelToNode(assignment.value); } + @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async assignEntryToPerson( @Arg("entryId") entryId: string, @@ -73,6 +91,7 @@ export class FundraisingAssignmentResolver { return fundraisingAssignmentModelToNode(assignment.value); } + @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async updateFundraisingAssignment( @Arg("id") id: string, @@ -90,6 +109,7 @@ export class FundraisingAssignmentResolver { return fundraisingAssignmentModelToNode(assignment.value); } + @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async deleteFundraisingAssignment( @Arg("id") id: string @@ -105,6 +125,8 @@ export class FundraisingAssignmentResolver { return fundraisingAssignmentModelToNode(assignment.value); } + // I'm fairly certain this is safe to leave without an access control check as anyone with + // access to the assignment should have access to the person @FieldResolver(() => PersonNode) async person( @Root() assignment: FundraisingAssignmentNode diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 8078f944..889aecfe 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -6,7 +6,6 @@ import { FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, - MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; import { @@ -20,10 +19,9 @@ import { Resolver, Root, } from "type-graphql"; -import { Container, Service } from "typedi"; +import { Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; -import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; @@ -134,49 +132,51 @@ export class FundraisingEntryResolver { }); } - @AccessControl( - // You can view assignments for an entry if you are: - // 1. A fundraising coordinator or chair - fundraisingAccess, - // 2. The captain of the team the entry is associated with - { - custom: async ( - { id }, - { teamMemberships, userData: { userId } } - ): Promise => { - if (userId == null) { - return false; - } - const captainOf = teamMemberships - .filter( - (membership) => - membership.position === MembershipPositionType.Captain - ) - .map((membership) => membership.teamId); - if (captainOf.length === 0) { - return false; - } + // I think this is actually unnecessary, as the only way to get to this resolver is through an + // already secured query + // @AccessControl( + // // You can view assignments for an entry if you are: + // // 1. A fundraising coordinator or chair + // fundraisingAccess, + // // 2. The captain of the team the entry is associated with + // { + // custom: async ( + // { id }, + // { teamMemberships, userData: { userId } } + // ): Promise => { + // if (userId == null) { + // return false; + // } + // const captainOf = teamMemberships + // .filter( + // (membership) => + // membership.position === MembershipPositionType.Captain + // ) + // .map((membership) => membership.teamId); + // if (captainOf.length === 0) { + // return false; + // } - const fundraisingEntryRepository = Container.get( - FundraisingEntryRepository - ); - const entry = await fundraisingEntryRepository.findEntryByUnique({ - uuid: id, - }); - if (entry.isErr) { - return false; - } - const dbFundsRepository = Container.get(DBFundsRepository); - const team = await dbFundsRepository.getTeamForDbFundsTeam({ - id: entry.value.dbFundsEntry.dbFundsTeamId, - }); - if (team.isErr) { - return false; - } - return captainOf.includes(team.value.uuid); - }, - } - ) + // const fundraisingEntryRepository = Container.get( + // FundraisingEntryRepository + // ); + // const entry = await fundraisingEntryRepository.findEntryByUnique({ + // uuid: id, + // }); + // if (entry.isErr) { + // return false; + // } + // const dbFundsRepository = Container.get(DBFundsRepository); + // const team = await dbFundsRepository.getTeamForDbFundsTeam({ + // id: entry.value.dbFundsEntry.dbFundsTeamId, + // }); + // if (team.isErr) { + // return false; + // } + // return captainOf.includes(team.value.uuid); + // }, + // } + // ) @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( @Root() entry: FundraisingEntryNode diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 0dc420ec..f9bd6b30 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -36,6 +36,9 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { CatchableConcreteError } from "../lib/formatError.js"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; +import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; import { membershipModelToResource } from "../repositories/membership/membershipModelToResource.js"; import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; @@ -47,6 +50,10 @@ import { AbstractGraphQLOkResponse, AbstractGraphQLPaginatedResponse, } from "./ApiResponse.js"; +import { + ListFundraisingEntriesArgs, + ListFundraisingEntriesResponse, +} from "./FundraisingEntryResolver.js"; import * as Context from "./context.js"; @ObjectType("SingleTeamResponse", { @@ -135,7 +142,10 @@ class ListTeamsArgs extends FilteredListQueryArgs< @Resolver(() => TeamNode) @Service() export class TeamResolver { - constructor(private teamRepository: TeamRepository) {} + constructor( + private teamRepository: TeamRepository, + private fundraisingEntryRepository: FundraisingEntryRepository + ) {} @AccessControl({ accessLevel: AccessLevel.Committee }) @Query(() => SingleTeamResponse, { name: "team" }) @@ -368,4 +378,66 @@ export class TeamResolver { return marathonModelToResource(result); } + + @AccessControl( + { accessLevel: AccessLevel.Committee }, + { + rootMatch: [ + { + root: "uuid", + extractor: ({ teamMemberships }) => + teamMemberships + .filter( + ({ position }) => + position === Common.MembershipPositionType.Captain + ) + .map(({ teamId }) => teamId), + }, + ], + } + ) + @FieldResolver(() => ListFundraisingEntriesResponse) + async fundraisingEntries( + @Root() team: TeamNode, + @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs + ): Promise { + const entries = await this.fundraisingEntryRepository.listEntries( + { + filters: args.filters, + order: + args.sortBy?.map((key, i) => [ + key, + args.sortDirection?.[i] ?? SortDirection.desc, + ]) ?? [], + skip: + args.page != null && args.pageSize != null + ? (args.page - 1) * args.pageSize + : null, + take: args.pageSize, + }, + { + // EXTREMELY IMPORTANT FOR SECURITY + forTeam: { uuid: team.id }, + } + ); + const count = await this.fundraisingEntryRepository.countEntries({ + filters: args.filters, + }); + + if (entries.isErr) { + throw new CatchableConcreteError(entries.error); + } + if (count.isErr) { + throw new CatchableConcreteError(count.error); + } + + return ListFundraisingEntriesResponse.newPaginated({ + data: await Promise.all( + entries.value.map((model) => fundraisingEntryModelToNode(model)) + ), + total: count.value, + page: args.page, + pageSize: args.pageSize, + }); + } } diff --git a/schema.graphql b/schema.graphql index 948817c0..55bb1ca2 100644 --- a/schema.graphql +++ b/schema.graphql @@ -2066,6 +2066,49 @@ enum TeamLegacyStatus { type TeamNode implements Node { captains: [MembershipNode!]! @deprecated(reason: "Just query the members field and filter by role") createdAt: DateTimeISO + fundraisingEntries( + """The boolean filters to apply to the query""" + booleanFilters: Void + + """The date filters to apply to the query""" + dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] + + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + + """The is-null filters to apply to the query""" + isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] + + """The numeric filters to apply to the query""" + numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] + + """The one-of filters to apply to the query""" + oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] + + """The page number to return, defaults to 1""" + page: Int + + """The number of items to return per page, defaults to 10""" + pageSize: Int + + """ + Whether to send all results in a single page, defaults to false (should generally be avoided) + """ + sendAll: Boolean + + """ + The fields to sort by, in order of priority. If unspecified, the sort order is undefined + """ + sortBy: [String!] + + """ + The direction to sort, if not specified will default to ascending, the order of the values in this array should match the order of the values in the sortBy array, if only one value is specified it will be used for all sortBy values, otherwise the lengths must match + """ + sortDirection: [SortDirection!] + + """The string filters to apply to the query""" + stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] + ): ListFundraisingEntriesResponse! id: ID! legacyStatus: TeamLegacyStatus! marathon: MarathonNode! From 68c3da04ecb31e85b9d044db4df177fb82ffc9f2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 7 Jun 2024 01:00:45 +0000 Subject: [PATCH 099/153] Wrap up initial fundraising tracking support --- .../common/lib/authorization/accessControl.ts | 16 ++++-- .../migration.sql | 29 +++++++++++ packages/server/src/jobs/syncDbFunds.ts | 6 ++- .../fundraising/DBFundsRepository.ts | 49 ++++++++++++++++--- .../server/src/resolvers/PersonResolver.ts | 8 +-- packages/server/src/resolvers/TeamResolver.ts | 6 +-- packages/server/src/resolvers/context.ts | 1 + 7 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 packages/server/prisma/migrations/20240606202016_more_fundraising/migration.sql diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index 75a6ace0..b20052bd 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -327,6 +327,7 @@ export function AccessControl( } if (rule.rootMatch != null) { + let shouldContinue = false; for (const match of rule.rootMatch) { const rootValue = typeof match.root === "string" @@ -343,19 +344,26 @@ export function AccessControl( if (Array.isArray(expectedValue)) { if (Array.isArray(rootValue)) { if (!rootValue.some((v) => expectedValue.includes(v))) { - continue; + shouldContinue = true; + break; } } else if (!expectedValue.includes(rootValue)) { - continue; + shouldContinue = true; + break; } } else if (Array.isArray(rootValue)) { if (!rootValue.includes(expectedValue)) { - continue; + shouldContinue = true; + break; } } else if (rootValue !== expectedValue) { - continue; + shouldContinue = true; + break; } } + if (shouldContinue) { + continue; + } } if (rule.custom != null) { diff --git a/packages/server/prisma/migrations/20240606202016_more_fundraising/migration.sql b/packages/server/prisma/migrations/20240606202016_more_fundraising/migration.sql new file mode 100644 index 00000000..47826fc7 --- /dev/null +++ b/packages/server/prisma/migrations/20240606202016_more_fundraising/migration.sql @@ -0,0 +1,29 @@ +/* + Warnings: + + - You are about to drop the column `db_funds_entry_date` on the `fundraising_entries` table. All the data in the column will be lost. + - You are about to drop the column `db_funds_entry_donated_by` on the `fundraising_entries` table. All the data in the column will be lost. + - You are about to drop the column `total_amount` on the `fundraising_entries` table. All the data in the column will be lost. + - A unique constraint covering the columns `[db_funds_entry_id]` on the table `fundraising_entries` will be added. If there are existing duplicate values, this will fail. + +*/ +-- DropForeignKey +ALTER TABLE "fundraising_entries" DROP CONSTRAINT "fundraising_entries_db_funds_entry_donated_by_db_funds_ent_fkey"; + +-- DropIndex +DROP INDEX "db_funds_team_entries_donated_by_date_key"; + +-- DropIndex +DROP INDEX "fundraising_entries_db_funds_entry_donated_by_date_key"; + +-- AlterTable +ALTER TABLE "fundraising_entries" DROP COLUMN "db_funds_entry_date", +DROP COLUMN "db_funds_entry_donated_by", +DROP COLUMN "total_amount", +ADD COLUMN "db_funds_entry_id" INTEGER; + +-- CreateIndex +CREATE UNIQUE INDEX "fundraising_entries_db_funds_entry_id_key" ON "fundraising_entries"("db_funds_entry_id"); + +-- AddForeignKey +ALTER TABLE "fundraising_entries" ADD CONSTRAINT "fundraising_entries_db_funds_entry_id_fkey" FOREIGN KEY ("db_funds_entry_id") REFERENCES "db_funds_team_entries"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index 2f9d94b3..06f8ffb1 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -77,7 +77,11 @@ async function doSync(): Promise< if (result.status === "rejected") { errors.push(toBasicError(result.reason)); } else if (result.value.isErr) { - errors.push(result.value.error); + if (result.value.error instanceof CompositeError) { + errors.push(...result.value.error.errors); + } else { + errors.push(result.value.error); + } } } diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index d09d528e..ead87ff3 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,9 +1,10 @@ import { PrismaClient, Team } from "@prisma/client"; -import type { DateTime } from "luxon"; -import { Maybe, Result } from "true-myth"; +import { DateTime } from "luxon"; +import { Maybe, Result, Unit } from "true-myth"; import { err, ok } from "true-myth/result"; import { Service } from "typedi"; +import { CompositeError } from "../../lib/error/composite.js"; import { NotFoundError } from "../../lib/error/direct.js"; import { BasicError, toBasicError } from "../../lib/error/error.js"; import { @@ -11,15 +12,17 @@ import { SomePrismaError, toPrismaError, } from "../../lib/error/prisma.js"; -import { type JsResult } from "../../lib/error/result.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; +import { FundraisingEntryRepository } from "./FundraisingRepository.js"; + @Service() export class DBFundsRepository { constructor( private readonly prisma: PrismaClient, - private readonly marathonRepository: MarathonRepository + private readonly marathonRepository: MarathonRepository, + private readonly fundraisingEntryRepository: FundraisingEntryRepository ) {} async overwriteTeamForFiscalYear( @@ -36,7 +39,15 @@ export class DBFundsRepository { donatedOn: DateTime; amount: number; }[] - ): Promise> { + ): Promise< + Result< + Unit, + | PrismaError + | NotFoundError + | CompositeError + | BasicError + > + > { try { let marathonId: number; if ("id" in marathonParam) { @@ -49,7 +60,7 @@ export class DBFundsRepository { } marathonId = marathon.id; } - await this.prisma.dBFundsTeam.upsert({ + const rows = await this.prisma.dBFundsTeam.upsert({ where: { dbNum_marathonId: { dbNum: team.dbNum, @@ -89,9 +100,33 @@ export class DBFundsRepository { })), }, }, + select: { + fundraisingEntries: true, + }, }); - return Result.ok(undefined); + const results = await Promise.allSettled( + rows.fundraisingEntries.map(async (entry) => { + return this.fundraisingEntryRepository.connectEntry(entry); + }) + ); + + const errors: (PrismaError | BasicError)[] = []; + for (const result of results) { + if (result.status === "rejected") { + errors.push( + toPrismaError(result.reason).unwrapOrElse(() => + toBasicError(result.reason) + ) + ); + } else if (result.value.isErr) { + errors.push(result.value.error); + } + } + + return errors.length > 0 + ? Result.err(new CompositeError(errors)) + : Result.ok(); } catch (error) { return Result.err( toPrismaError(error).unwrapOrElse(() => toBasicError(error)) diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index ad09152c..e1922b8e 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -340,7 +340,7 @@ export class PersonResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ userData }) => userData.userId, }, ], @@ -373,7 +373,7 @@ export class PersonResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ userData }) => userData.userId, }, ], @@ -401,7 +401,7 @@ export class PersonResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ userData }) => userData.userId, }, ], @@ -429,7 +429,7 @@ export class PersonResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ userData }) => userData.userId, }, ], diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index f9bd6b30..952f3024 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -307,7 +307,7 @@ export class TeamResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ teamMemberships }) => teamMemberships.map(({ teamId }) => teamId), }, @@ -341,7 +341,7 @@ export class TeamResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ teamMemberships }) => teamMemberships.map(({ teamId }) => teamId), }, @@ -384,7 +384,7 @@ export class TeamResolver { { rootMatch: [ { - root: "uuid", + root: "id", extractor: ({ teamMemberships }) => teamMemberships .filter( diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 885c6b22..3d4556e9 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -76,6 +76,7 @@ export const graphqlContextFunction: ContextFunction< ); logger.trace("graphqlContextFunction Found user", personResource); context.authenticatedUser = personResource; + context.userData.userId = userId; // Set the committees the user is on const committeeMemberships = From 696052893c364a425549f659bcc98e47a3e3157f Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 7 Jun 2024 21:00:35 +0000 Subject: [PATCH 100/153] Add an entry point to fundraising assignments under person --- .../src/resolvers/FundraisingEntryResolver.ts | 24 ++++--- .../server/src/resolvers/PersonResolver.ts | 64 ++++++++++++++++++- packages/server/src/resolvers/TeamResolver.ts | 32 +++++----- 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 889aecfe..63ca982a 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -65,14 +65,18 @@ export class ListFundraisingEntriesResponse extends AbstractGraphQLPaginatedResp data!: FundraisingEntryNode[]; } -const fundraisingAccess: AccessControlParam = { - authRules: [ - { - minCommitteeRole: CommitteeRole.Coordinator, - committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], - }, - ], -}; +/** + * Access control param for granting access to all fundraising entries. + */ +export const globalFundraisingAccessParam: AccessControlParam = + { + authRules: [ + { + minCommitteeRole: CommitteeRole.Coordinator, + committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], + }, + ], + }; @Resolver(() => FundraisingEntryNode) @Service() @@ -81,7 +85,7 @@ export class FundraisingEntryResolver { private readonly fundraisingEntryRepository: FundraisingEntryRepository ) {} - @AccessControl(fundraisingAccess) + @AccessControl(globalFundraisingAccessParam) @Query(() => FundraisingEntryNode) async fundraisingEntry(@Arg("id") id: string): Promise { const entry = await this.fundraisingEntryRepository.findEntryByUnique({ @@ -93,7 +97,7 @@ export class FundraisingEntryResolver { return fundraisingEntryModelToNode(entry.value); } - @AccessControl(fundraisingAccess) + @AccessControl(globalFundraisingAccessParam) @Query(() => ListFundraisingEntriesResponse) async fundraisingEntries( @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index e1922b8e..dc81e2d1 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -29,7 +29,10 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; +import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; +import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { committeeMembershipModelToResource, @@ -44,6 +47,11 @@ import { AbstractGraphQLOkResponse, AbstractGraphQLPaginatedResponse, } from "./ApiResponse.js"; +import { + ListFundraisingEntriesArgs, + ListFundraisingEntriesResponse, + globalFundraisingAccessParam, +} from "./FundraisingEntryResolver.js"; import type { GraphQLContext } from "./context.js"; @ObjectType("CreatePersonResponse", { @@ -149,7 +157,8 @@ class SetPersonInput { export class PersonResolver { constructor( private readonly personRepository: PersonRepository, - private readonly membershipRepository: MembershipRepository + private readonly membershipRepository: MembershipRepository, + private readonly fundraisingEntryRepository: FundraisingEntryRepository ) {} @AccessControl({ accessLevel: AccessLevel.Committee }) @@ -451,4 +460,57 @@ export class PersonResolver { return committeeMembershipModelToResource(membership, committee.identifier); } + + @AccessControl(globalFundraisingAccessParam, { + rootMatch: [ + { + root: "id", + extractor: ({ userData }) => userData.userId, + }, + ], + }) + @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) + async assignedDonations( + @Root() person: PersonNode, + @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs + ): Promise { + const entries = await this.fundraisingEntryRepository.listEntries( + { + filters: args.filters, + order: + args.sortBy?.map((key, i) => [ + key, + args.sortDirection?.[i] ?? SortDirection.desc, + ]) ?? [], + skip: + args.page != null && args.pageSize != null + ? (args.page - 1) * args.pageSize + : null, + take: args.pageSize, + }, + { + // EXTREMELY IMPORTANT FOR SECURITY + assignedToPerson: { uuid: person.id }, + } + ); + const count = await this.fundraisingEntryRepository.countEntries({ + filters: args.filters, + }); + + if (entries.isErr) { + throw new CatchableConcreteError(entries.error); + } + if (count.isErr) { + throw new CatchableConcreteError(count.error); + } + + return ListFundraisingEntriesResponse.newPaginated({ + data: await Promise.all( + entries.value.map((model) => fundraisingEntryModelToNode(model)) + ), + total: count.value, + page: args.page, + pageSize: args.pageSize, + }); + } } diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 952f3024..926a3b2c 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -53,6 +53,7 @@ import { import { ListFundraisingEntriesArgs, ListFundraisingEntriesResponse, + globalFundraisingAccessParam, } from "./FundraisingEntryResolver.js"; import * as Context from "./context.js"; @@ -379,23 +380,20 @@ export class TeamResolver { return marathonModelToResource(result); } - @AccessControl( - { accessLevel: AccessLevel.Committee }, - { - rootMatch: [ - { - root: "id", - extractor: ({ teamMemberships }) => - teamMemberships - .filter( - ({ position }) => - position === Common.MembershipPositionType.Captain - ) - .map(({ teamId }) => teamId), - }, - ], - } - ) + @AccessControl(globalFundraisingAccessParam, { + rootMatch: [ + { + root: "id", + extractor: ({ teamMemberships }) => + teamMemberships + .filter( + ({ position }) => + position === Common.MembershipPositionType.Captain + ) + .map(({ teamId }) => teamId), + }, + ], + }) @FieldResolver(() => ListFundraisingEntriesResponse) async fundraisingEntries( @Root() team: TeamNode, From fd7c4ea2d2ff0bd158f1bc81a16945131b741ef1 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 9 Jun 2024 03:55:43 +0000 Subject: [PATCH 101/153] Some fundraising stuff --- .../lib/graphql-client-admin/graphql.ts | 17 ++++ .../lib/graphql-client-public/graphql.ts | 17 ++++ .../migration.sql | 2 + packages/server/prisma/schema.prisma | 6 +- .../fundraising/DBFundsRepository.ts | 37 ++++++-- .../fundraising/FundraisingRepository.ts | 56 ++++++++++++ .../fundraisingEntryRepositoryUtils.ts | 2 +- .../FundraisingAssignmentResolver.ts | 15 ++++ .../src/resolvers/FundraisingEntryResolver.ts | 90 +++++++++---------- .../server/src/resolvers/PersonResolver.ts | 86 ++++++++++++++++-- packages/server/src/resolvers/TeamResolver.ts | 45 +++++++++- schema.graphql | 43 +++++++++ 12 files changed, 351 insertions(+), 65 deletions(-) create mode 100644 packages/server/prisma/migrations/20240609033749_multiple_dbfunds_teams/migration.sql diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 9aeed0a2..e131aba9 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -1428,6 +1428,7 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; + readonly assignedDonations?: Maybe; readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; @@ -1441,6 +1442,22 @@ export type PersonNode = Node & { readonly updatedAt?: Maybe; }; + +export type PersonNodeAssignedDonationsArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + export const PersonResolverAllKeys = { CommitteeName: 'committeeName', CommitteeRole: 'committeeRole', diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index df3a2468..6cabf3d4 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -1428,6 +1428,7 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; + readonly assignedDonations?: Maybe; readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; @@ -1441,6 +1442,22 @@ export type PersonNode = Node & { readonly updatedAt?: Maybe; }; + +export type PersonNodeAssignedDonationsArgs = { + booleanFilters?: InputMaybe; + dateFilters?: InputMaybe>; + includeDeleted?: InputMaybe; + isNullFilters?: InputMaybe>; + numericFilters?: InputMaybe>; + oneOfFilters?: InputMaybe>; + page?: InputMaybe; + pageSize?: InputMaybe; + sendAll?: InputMaybe; + sortBy?: InputMaybe>; + sortDirection?: InputMaybe>; + stringFilters?: InputMaybe>; +}; + export const PersonResolverAllKeys = { CommitteeName: 'committeeName', CommitteeRole: 'committeeRole', diff --git a/packages/server/prisma/migrations/20240609033749_multiple_dbfunds_teams/migration.sql b/packages/server/prisma/migrations/20240609033749_multiple_dbfunds_teams/migration.sql new file mode 100644 index 00000000..80855b13 --- /dev/null +++ b/packages/server/prisma/migrations/20240609033749_multiple_dbfunds_teams/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "teams_db_funds_team_id_key"; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 8a6a2974..01e16618 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -243,7 +243,7 @@ model Team { correspondingCommittee Committee? @relation(fields: [correspondingCommitteeId], references: [id]) correspondingCommitteeId Int? @map("committee_id") dbFundsTeam DBFundsTeam? @relation(fields: [dbFundsTeamId], references: [id]) - dbFundsTeamId Int? @unique @map("db_funds_team_id") + dbFundsTeamId Int? @map("db_funds_team_id") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) @@ -421,8 +421,8 @@ model DBFundsTeam { marathon Marathon? @relation(fields: [marathonId], references: [id]) marathonId Int? @map("marathon_id") - // The corresponding team in our database - team Team? + // The corresponding teams in our database + teams Team[] @@unique([dbNum, marathonId], map: "db_funds_teams_db_num_marathon_id_key") @@map("db_funds_teams") diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index ead87ff3..5c47905f 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,4 +1,4 @@ -import { PrismaClient, Team } from "@prisma/client"; +import { DBFundsTeam, PrismaClient, Team } from "@prisma/client"; import { DateTime } from "luxon"; import { Maybe, Result, Unit } from "true-myth"; import { err, ok } from "true-myth/result"; @@ -134,18 +134,43 @@ export class DBFundsRepository { } } - async getTeamForDbFundsTeam(dbFundsTeamParam: { + async getTeamsForDbFundsTeam(dbFundsTeamParam: { id: number; - }): Promise> { + }): Promise> { try { const team = await this.prisma.dBFundsTeam.findUnique({ where: dbFundsTeamParam, - include: { team: true }, + include: { teams: true }, }); - if (!team?.team) { + if (!team) { return err(new NotFoundError({ what: "Team" })); } - return ok(team.team); + return ok(team.teams); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async listDbFundsTeams(search: { + byDbNum?: number; + byName?: string; + onlyActive?: boolean; + }): Promise> { + try { + return ok( + await this.prisma.dBFundsTeam.findMany({ + where: { + active: search.onlyActive ? true : undefined, + dbNum: search.byDbNum, + name: { + contains: search.byName, + }, + }, + orderBy: { + name: "asc", + }, + }) + ); } catch (error) { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index d84f9fba..965a269d 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -16,6 +16,7 @@ import { NotFoundError } from "../../lib/error/direct.js"; import { BasicError, toBasicError } from "../../lib/error/error.js"; import { SomePrismaError, toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { UniquePersonParam } from "../person/PersonRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import { @@ -426,4 +427,59 @@ export class FundraisingEntryRepository { return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } + + async getEntryForAssignment( + assignmentParam: FundraisingAssignmentUniqueParam + ): Promise< + Result< + FundraisingEntry & { + dbFundsEntry: DBFundsFundraisingEntry; + }, + SomePrismaError | BasicError | NotFoundError + > + > { + try { + const assignment = await this.prisma.fundraisingAssignment.findUnique({ + where: assignmentParam, + select: { + parentEntry: { + include: defaultInclude, + }, + }, + }); + if (!assignment) { + return err(new NotFoundError({ what: "FundraisingAssignment" })); + } + if (!assignment.parentEntry.dbFundsEntry) { + return err( + new NotFoundError({ what: "FundraisingEntry.dbFundsEntry" }) + ); + } + return ok( + assignment.parentEntry as typeof assignment.parentEntry & { + dbFundsEntry: NonNullable; + } + ); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async getAssignmentsForPerson( + personParam: UniquePersonParam + ): Promise< + Result< + readonly FundraisingAssignment[], + SomePrismaError | BasicError | NotFoundError + > + > { + try { + const assignments = await this.prisma.fundraisingAssignment.findMany({ + where: { person: personParam }, + }); + return ok(assignments); + } catch (error: unknown) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } } diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index 3668c15a..cee2dc96 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -92,7 +92,7 @@ export function buildFundraisingEntryWhere( } case "teamId": { dbFundsEntryWhere.dbFundsTeam = { - team: { uuid: oneOfFilterToPrisma(filter) }, + teams: { some: { uuid: oneOfFilterToPrisma(filter) } }, }; break; } diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 9432ec8c..c95fadd1 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -4,6 +4,7 @@ import { CommitteeIdentifier, CommitteeRole, FundraisingAssignmentNode, + FundraisingEntryNode, PersonNode, } from "@ukdanceblue/common"; import { @@ -21,6 +22,7 @@ import { Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; @@ -139,4 +141,17 @@ export class FundraisingAssignmentResolver { } return personModelToResource(person.value, this.personRepository); } + + @FieldResolver(() => FundraisingEntryNode) + async entry( + @Root() assignment: FundraisingAssignmentNode + ): Promise { + const entry = await this.fundraisingEntryRepository.getEntryForAssignment({ + uuid: assignment.id, + }); + if (entry.isErr) { + throw new CatchableConcreteError(entry.error); + } + return fundraisingEntryModelToNode(entry.value); + } } diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 63ca982a..e05bab1d 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -6,6 +6,7 @@ import { FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, + MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; import { @@ -19,9 +20,10 @@ import { Resolver, Root, } from "type-graphql"; -import { Service } from "typedi"; +import { Container, Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; +import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; @@ -136,51 +138,49 @@ export class FundraisingEntryResolver { }); } - // I think this is actually unnecessary, as the only way to get to this resolver is through an - // already secured query - // @AccessControl( - // // You can view assignments for an entry if you are: - // // 1. A fundraising coordinator or chair - // fundraisingAccess, - // // 2. The captain of the team the entry is associated with - // { - // custom: async ( - // { id }, - // { teamMemberships, userData: { userId } } - // ): Promise => { - // if (userId == null) { - // return false; - // } - // const captainOf = teamMemberships - // .filter( - // (membership) => - // membership.position === MembershipPositionType.Captain - // ) - // .map((membership) => membership.teamId); - // if (captainOf.length === 0) { - // return false; - // } + @AccessControl( + // We can't grant blanket access as otherwise people would see who else was assigned to an entry + // You can view all assignments for an entry if you are: + // 1. A fundraising coordinator or chair + globalFundraisingAccessParam, + // 2. The captain of the team the entry is associated with + { + custom: async ( + { id }, + { teamMemberships, userData: { userId } } + ): Promise => { + if (userId == null) { + return false; + } + const captainOf = teamMemberships.filter( + (membership) => membership.position === MembershipPositionType.Captain + ); + if (captainOf.length === 0) { + return false; + } - // const fundraisingEntryRepository = Container.get( - // FundraisingEntryRepository - // ); - // const entry = await fundraisingEntryRepository.findEntryByUnique({ - // uuid: id, - // }); - // if (entry.isErr) { - // return false; - // } - // const dbFundsRepository = Container.get(DBFundsRepository); - // const team = await dbFundsRepository.getTeamForDbFundsTeam({ - // id: entry.value.dbFundsEntry.dbFundsTeamId, - // }); - // if (team.isErr) { - // return false; - // } - // return captainOf.includes(team.value.uuid); - // }, - // } - // ) + const fundraisingEntryRepository = Container.get( + FundraisingEntryRepository + ); + const entry = await fundraisingEntryRepository.findEntryByUnique({ + uuid: id, + }); + if (entry.isErr) { + return false; + } + const dbFundsRepository = Container.get(DBFundsRepository); + const teams = await dbFundsRepository.getTeamsForDbFundsTeam({ + id: entry.value.dbFundsEntry.dbFundsTeamId, + }); + if (teams.isErr) { + return false; + } + return captainOf.some(({ teamId }) => + teams.value.some((team) => team.uuid === teamId) + ); + }, + } + ) @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( @Root() entry: FundraisingEntryNode diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index dc81e2d1..5b0cd84d 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -7,6 +7,8 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, + FundraisingAssignmentNode, + FundraisingEntryNode, MembershipNode, MembershipPositionType, PersonNode, @@ -27,11 +29,13 @@ import { Resolver, Root, } from "type-graphql"; -import { Service } from "typedi"; +import { Container, Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; +import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; +import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { @@ -461,16 +465,51 @@ export class PersonResolver { return committeeMembershipModelToResource(membership, committee.identifier); } - @AccessControl(globalFundraisingAccessParam, { - rootMatch: [ - { - root: "id", - extractor: ({ userData }) => userData.userId, + @AccessControl( + // We can't grant blanket access as otherwise people would see who else was assigned to an entry + // You can view all assignments for an entry if you are: + // 1. A fundraising coordinator or chair + globalFundraisingAccessParam, + // 2. The captain of the team the entry is associated with + { + custom: async ( + { id }, + { teamMemberships, userData: { userId } } + ): Promise => { + if (userId == null) { + return false; + } + const captainOf = teamMemberships.filter( + (membership) => membership.position === MembershipPositionType.Captain + ); + if (captainOf.length === 0) { + return false; + } + + const fundraisingEntryRepository = Container.get( + FundraisingEntryRepository + ); + const entry = await fundraisingEntryRepository.findEntryByUnique({ + uuid: id, + }); + if (entry.isErr) { + return false; + } + const dbFundsRepository = Container.get(DBFundsRepository); + const teams = await dbFundsRepository.getTeamsForDbFundsTeam({ + id: entry.value.dbFundsEntry.dbFundsTeamId, + }); + if (teams.isErr) { + return false; + } + return captainOf.some(({ teamId }) => + teams.value.some((team) => team.uuid === teamId) + ); }, - ], - }) + } + ) @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) - async assignedDonations( + async assignedDonationEntries( @Root() person: PersonNode, @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs ): Promise { @@ -513,4 +552,33 @@ export class PersonResolver { pageSize: args.pageSize, }); } + + // This is the only way normal dancers or committee members can access fundraising info + // as it will only grant them the individual assignment they are associated with plus + // shallow access to the entry itself + @AccessControl({ + rootMatch: [ + { + root: "id", + extractor: ({ userData }) => userData.userId, + }, + ], + }) + @FieldResolver(() => [FundraisingAssignmentNode]) + async fundraisingAssignments( + @Root() person: PersonNode + ): Promise { + const models = + await this.fundraisingEntryRepository.getAssignmentsForPerson({ + uuid: person.id, + }); + + if (models.isErr) { + throw new CatchableConcreteError(models.error); + } + + return Promise.all( + models.value.map((row) => fundraisingAssignmentModelToNode(row)) + ); + } } diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 926a3b2c..28920b86 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -37,6 +37,7 @@ import { import { Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; +import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; @@ -140,12 +141,22 @@ class ListTeamsArgs extends FilteredListQueryArgs< marathonYear!: MarathonYearString[] | null; } +@ObjectType("DbFundsTeamInfo", { implements: [Common.Node] }) +class DbFundsTeamInfo { + @Field(() => Int) + dbNum!: number; + + @Field(() => String) + name!: string; +} + @Resolver(() => TeamNode) @Service() export class TeamResolver { constructor( private teamRepository: TeamRepository, - private fundraisingEntryRepository: FundraisingEntryRepository + private fundraisingEntryRepository: FundraisingEntryRepository, + private dbFundsRepository: DBFundsRepository ) {} @AccessControl({ accessLevel: AccessLevel.Committee }) @@ -438,4 +449,36 @@ export class TeamResolver { pageSize: args.pageSize, }); } + + @AccessControl(globalFundraisingAccessParam) + @Query(() => [DbFundsTeamInfo], { name: "dbFundsTeams" }) + async dbFundsTeams( + @Arg("search") search: string + ): Promise { + const searchParam: { + byDbNum?: number; + byName?: string; + } = {}; + const searchAsNum = Number.parseInt(search, 10); + if (Number.isInteger(searchAsNum)) { + searchParam.byDbNum = searchAsNum; + } else { + searchParam.byName = search; + } + const rows = await this.dbFundsRepository.listDbFundsTeams({ + ...searchParam, + onlyActive: true, + }); + + if (rows.isErr) { + throw new CatchableConcreteError(rows.error); + } + + return rows.value.map((row) => { + const teamInfoInstance = new DbFundsTeamInfo(); + teamInfoInstance.dbNum = row.dbNum; + teamInfoInstance.name = row.name; + return teamInfoInstance; + }); + } } diff --git a/schema.graphql b/schema.graphql index 55bb1ca2..b3ef2cce 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1228,6 +1228,49 @@ enum NumericComparator { } type PersonNode implements Node { + assignedDonations( + """The boolean filters to apply to the query""" + booleanFilters: Void + + """The date filters to apply to the query""" + dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] + + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + + """The is-null filters to apply to the query""" + isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] + + """The numeric filters to apply to the query""" + numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] + + """The one-of filters to apply to the query""" + oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] + + """The page number to return, defaults to 1""" + page: Int + + """The number of items to return per page, defaults to 10""" + pageSize: Int + + """ + Whether to send all results in a single page, defaults to false (should generally be avoided) + """ + sendAll: Boolean + + """ + The fields to sort by, in order of priority. If unspecified, the sort order is undefined + """ + sortBy: [String!] + + """ + The direction to sort, if not specified will default to ascending, the order of the values in this array should match the order of the values in the sortBy array, if only one value is specified it will be used for all sortBy values, otherwise the lengths must match + """ + sortDirection: [SortDirection!] + + """The string filters to apply to the query""" + stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] + ): CommitteeMembershipNode committees: [CommitteeMembershipNode!]! createdAt: DateTimeISO dbRole: DbRole! From 021380a4e19572e11a69661dd8f2dd8880fa7928 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 9 Jun 2024 04:44:22 +0000 Subject: [PATCH 102/153] Add assignTeamToDbFundsTeam mutation --- .../fundraising/DBFundsRepository.ts | 66 +++++++++++++++++-- packages/server/src/resolvers/TeamResolver.ts | 19 ++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 5c47905f..20d3f5ef 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -14,9 +14,19 @@ import { } from "../../lib/error/prisma.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; +import { SimpleUniqueParam } from "../shared.js"; import { FundraisingEntryRepository } from "./FundraisingRepository.js"; +export type UniqueDbFundsTeamParam = + | { + id: number; + } + | { + dbNum: number; + marathon: { id: number }; + }; + @Service() export class DBFundsRepository { constructor( @@ -134,12 +144,20 @@ export class DBFundsRepository { } } - async getTeamsForDbFundsTeam(dbFundsTeamParam: { - id: number; - }): Promise> { + async getTeamsForDbFundsTeam( + dbFundsTeamParam: UniqueDbFundsTeamParam + ): Promise> { try { const team = await this.prisma.dBFundsTeam.findUnique({ - where: dbFundsTeamParam, + where: + "marathon" in dbFundsTeamParam + ? { + dbNum_marathonId: { + dbNum: dbFundsTeamParam.dbNum, + marathonId: dbFundsTeamParam.marathon.id, + }, + } + : dbFundsTeamParam, include: { teams: true }, }); if (!team) { @@ -151,6 +169,46 @@ export class DBFundsRepository { } } + async assignTeamToDbFundsTeam( + teamParam: SimpleUniqueParam, + dbFundsTeamParam: + | UniqueDbFundsTeamParam + | { + dbNum: number; + } + ): Promise> { + try { + const team = await this.prisma.team.findUnique({ + where: teamParam, + }); + if (!team) { + return err(new NotFoundError({ what: "Team" })); + } + await this.prisma.dBFundsTeam.update({ + where: + "dbNum" in dbFundsTeamParam + ? { + dbNum_marathonId: { + dbNum: dbFundsTeamParam.dbNum, + marathonId: + "marathon" in dbFundsTeamParam + ? dbFundsTeamParam.marathon.id + : team.marathonId, + }, + } + : dbFundsTeamParam, + data: { + teams: { + connect: { id: team.id }, + }, + }, + }); + return ok(); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + async listDbFundsTeams(search: { byDbNum?: number; byName?: string; diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 28920b86..4ab759c7 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -19,6 +19,7 @@ import { TeamNode, TeamType, } from "@ukdanceblue/common"; +import { VoidResolver } from "graphql-scalars"; import { Arg, Args, @@ -481,4 +482,22 @@ export class TeamResolver { return teamInfoInstance; }); } + + @AccessControl(globalFundraisingAccessParam) + @Mutation(() => VoidResolver, { name: "assignTeamToDbFundsTeam" }) + async assignTeamToDbFundsTeam( + @Arg("teamId") teamId: string, + @Arg("dbFundsTeamId") dbFundsTeamId: number + ): Promise { + const result = await this.dbFundsRepository.assignTeamToDbFundsTeam( + { uuid: teamId }, + { dbNum: dbFundsTeamId } + ); + + if (result.isErr) { + throw new CatchableConcreteError(result.error); + } + + return undefined; + } } From e1e385a8353f388ba5fbee3af7b90714fb05bff5 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 13 Jun 2024 21:11:56 +0000 Subject: [PATCH 103/153] Update authorization context to include effective committee roles --- .../lib/api/types/EffectiveCommitteeRole.ts | 6 ++--- .../common/lib/authorization/accessControl.ts | 24 ----------------- packages/common/lib/authorization/role.ts | 23 ++++++++-------- .../common/lib/authorization/structures.ts | 13 +++++----- .../lib/graphql-client-admin/graphql.ts | 26 +++++++++++++++++-- .../lib/graphql-client-public/graphql.ts | 26 +++++++++++++++++-- .../fundraising/FundraisingRepository.ts | 6 +++-- .../repositories/person/PersonRepository.ts | 7 ++++- packages/server/src/resolvers/LoginState.ts | 2 +- packages/server/src/resolvers/context.ts | 3 +-- schema.graphql | 14 ++++++++-- 11 files changed, 94 insertions(+), 56 deletions(-) diff --git a/packages/common/lib/api/types/EffectiveCommitteeRole.ts b/packages/common/lib/api/types/EffectiveCommitteeRole.ts index d038c16b..45a76e62 100644 --- a/packages/common/lib/api/types/EffectiveCommitteeRole.ts +++ b/packages/common/lib/api/types/EffectiveCommitteeRole.ts @@ -8,17 +8,17 @@ import { @ObjectType("EffectiveCommitteeRole") export class EffectiveCommitteeRole { @Field(() => CommitteeIdentifier) - committee!: CommitteeIdentifier; + identifier!: CommitteeIdentifier; @Field(() => CommitteeRole) role!: CommitteeRole; public static init( - committee: CommitteeIdentifier, + identifier: CommitteeIdentifier, role: CommitteeRole ): EffectiveCommitteeRole { const effectiveCommitteeRole = new this(); - effectiveCommitteeRole.committee = committee; + effectiveCommitteeRole.identifier = identifier; effectiveCommitteeRole.role = role; return effectiveCommitteeRole; } diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index b20052bd..bc37d85d 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -7,7 +7,6 @@ import type { Authorization, CommitteeRole, DbRole, - EffectiveCommitteeRole, MembershipPositionType, PersonNode, TeamType, @@ -126,19 +125,14 @@ export async function checkAuthorization( // Access Level if (accessLevel != null) { matches &&= authorization.accessLevel >= accessLevel; - console.log( - `Access level ${authorization.accessLevel} >= ${accessLevel}: ${matches}` - ); } // DB role if (dbRole != null) { matches &&= authorization.dbRole === dbRole; - console.log(`DB role ${authorization.dbRole} === ${dbRole}: ${matches}`); } if (minDbRole != null) { matches &&= compareDbRole(authorization.dbRole, minDbRole) >= 0; - console.log(`DB role ${authorization.dbRole} >= ${minDbRole}: ${matches}`); } // Committee role @@ -152,17 +146,11 @@ export async function checkAuthorization( if (minCommitteeRole != null) { if (authorization.committees.length === 0) { matches = false; - console.log(`No committee roles: ${matches}`); } else { matches &&= authorization.committees.some( (committee) => compareCommitteeRole(committee.role, minCommitteeRole) >= 0 ); - console.log( - `Committee role ${authorization.committees - .map((c) => c.role) - .join(", ")} >= ${minCommitteeRole}: ${matches}` - ); } } @@ -171,21 +159,11 @@ export async function checkAuthorization( matches &&= authorization.committees.some( (committee) => committee.identifier === committeeIdentifier ); - console.log( - `Committee identifier ${authorization.committees - .map((c) => c.identifier) - .join(", ")} === ${committeeIdentifier}: ${matches}` - ); } if (committeeIdentifiers != null) { matches &&= authorization.committees.some((committee) => committeeIdentifiers.includes(committee.identifier) ); - console.log( - `Committee identifier ${authorization.committees - .map((c) => c.identifier) - .join(", ")} in ${committeeIdentifiers.join(", ")}: ${matches}` - ); } // Custom auth checker @@ -197,7 +175,6 @@ export async function checkAuthorization( interface ExtractorData { authenticatedUser: PersonNode | null; - effectiveCommitteeRoles: EffectiveCommitteeRole[]; teamMemberships: SimpleTeamMembership[]; userData: UserData; authorization: Authorization; @@ -244,7 +221,6 @@ export interface SimpleTeamMembership { export interface AuthorizationContext { authenticatedUser: PersonNode | null; - effectiveCommitteeRoles: EffectiveCommitteeRole[]; teamMemberships: SimpleTeamMembership[]; userData: UserData; authorization: Authorization; diff --git a/packages/common/lib/authorization/role.ts b/packages/common/lib/authorization/role.ts index 92c112fa..26aaba28 100644 --- a/packages/common/lib/authorization/role.ts +++ b/packages/common/lib/authorization/role.ts @@ -5,11 +5,6 @@ import { DbRole, } from "./structures.js"; -export type Role = { - dbRole: DbRole; - committees?: { identifier: CommitteeIdentifier; role: CommitteeRole }[]; -}; - /** * Converts a DbRole to an AccessLevel * @@ -17,8 +12,14 @@ export type Role = { * @return The equivalent AccessLevel * @throws Error if the DbRole is not a valid member of the DbRole enum */ -export function roleToAccessLevel(role: Role): AccessLevel { - switch (role.dbRole) { +export function roleToAccessLevel({ + dbRole, + committees, +}: { + dbRole: DbRole; + committees?: { identifier: CommitteeIdentifier; role: CommitteeRole }[]; +}): AccessLevel { + switch (dbRole) { case DbRole.None: { return AccessLevel.None; } @@ -30,7 +31,7 @@ export function roleToAccessLevel(role: Role): AccessLevel { } case DbRole.Committee: { let maxLevel: AccessLevel | null = null; - for (const committee of role.committees ?? []) { + for (const committee of committees ?? []) { let thisLevel: AccessLevel; if (committee.identifier === CommitteeIdentifier.techCommittee) { @@ -54,12 +55,12 @@ export function roleToAccessLevel(role: Role): AccessLevel { return maxLevel; } default: { - role.dbRole satisfies never; + dbRole satisfies never; try { - throw new Error(`Illegal DbRole: ${JSON.stringify(role.dbRole)}`); + throw new Error(`Illegal DbRole: ${JSON.stringify(dbRole)}`); } catch (error) { throw new Error( - `Illegal DbRole: [Parsing of '${String(role.dbRole)}' failed]` + `Illegal DbRole: [Parsing of '${String(dbRole)}' failed]` ); } } diff --git a/packages/common/lib/authorization/structures.ts b/packages/common/lib/authorization/structures.ts index 0624b3aa..dcd5acc4 100644 --- a/packages/common/lib/authorization/structures.ts +++ b/packages/common/lib/authorization/structures.ts @@ -1,5 +1,7 @@ import { registerEnumType } from "type-graphql"; +import type { EffectiveCommitteeRole } from "../api/types/EffectiveCommitteeRole.js"; + export const AuthSource = { LinkBlue: "LinkBlue", Anonymous: "Anonymous", @@ -28,7 +30,8 @@ export const AccessLevel = { UKY: 1, Committee: 3, CommitteeChairOrCoordinator: 3.5, - Admin: 4, // Tech committee + Admin: 4, + SuperAdmin: 5, // App & Web Coordinators and Tech chair - master override access } as const; export type AccessLevel = (typeof AccessLevel)[keyof typeof AccessLevel]; @@ -76,7 +79,8 @@ export function stringifyAccessLevel(val: unknown): string { case AccessLevel.CommitteeChairOrCoordinator: { return "Committee Chair/Coordinator"; } - case AccessLevel.Admin: { + case AccessLevel.Admin: + case AccessLevel.SuperAdmin: { return "Admin"; } } @@ -263,10 +267,7 @@ export const committeeNames: Record = { export interface Authorization { dbRole: DbRole; - committees: { - identifier: CommitteeIdentifier; - role: CommitteeRole; - }[]; + committees: EffectiveCommitteeRole[]; accessLevel: AccessLevel; } diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index e131aba9..122a6f8d 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -251,6 +251,13 @@ export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQ readonly uuid: Scalars['String']['output']; }; +export type DbFundsTeamInfo = Node & { + readonly __typename?: 'DbFundsTeamInfo'; + readonly dbNum: Scalars['Int']['output']; + readonly id: Scalars['ID']['output']; + readonly name: Scalars['String']['output']; +}; + export { DbRole }; export type DeleteConfigurationResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { @@ -476,6 +483,7 @@ export type FundraisingAssignmentNode = Node & { readonly __typename?: 'FundraisingAssignmentNode'; readonly amount: Scalars['Float']['output']; readonly createdAt?: Maybe; + readonly entry: FundraisingEntryNode; readonly id: Scalars['ID']['output']; readonly person: PersonNode; readonly updatedAt?: Maybe; @@ -960,6 +968,7 @@ export type Mutation = { readonly addMap: MarathonHourNode; readonly addPersonToTeam: GetMembershipResponse; readonly assignEntryToPerson: FundraisingAssignmentNode; + readonly assignTeamToDbFundsTeam: Scalars['Void']['output']; readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; @@ -1041,6 +1050,12 @@ export type MutationAssignEntryToPersonArgs = { }; +export type MutationAssignTeamToDbFundsTeamArgs = { + dbFundsTeamId: Scalars['Float']['input']; + teamId: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -1428,11 +1443,12 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; - readonly assignedDonations?: Maybe; + readonly assignedDonationEntries?: Maybe; readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; readonly email: Scalars['String']['output']; + readonly fundraisingAssignments: ReadonlyArray; readonly id: Scalars['ID']['output']; readonly linkblue?: Maybe; readonly moraleTeams: ReadonlyArray; @@ -1443,7 +1459,7 @@ export type PersonNode = Node & { }; -export type PersonNodeAssignedDonationsArgs = { +export type PersonNodeAssignedDonationEntriesArgs = { booleanFilters?: InputMaybe; dateFilters?: InputMaybe>; includeDeleted?: InputMaybe; @@ -1626,6 +1642,7 @@ export type Query = { readonly allConfigurations: GetAllConfigurationsResponse; readonly currentMarathon?: Maybe; readonly currentMarathonHour?: Maybe; + readonly dbFundsTeams: ReadonlyArray; readonly device: GetDeviceByUuidResponse; readonly devices: ListDevicesResponse; readonly event: GetEventByUuidResponse; @@ -1664,6 +1681,11 @@ export type QueryActiveConfigurationArgs = { }; +export type QueryDbFundsTeamsArgs = { + search: Scalars['String']['input']; +}; + + export type QueryDeviceArgs = { uuid: Scalars['String']['input']; }; diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 6cabf3d4..ef77d236 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -251,6 +251,13 @@ export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQ readonly uuid: Scalars['String']['output']; }; +export type DbFundsTeamInfo = Node & { + readonly __typename?: 'DbFundsTeamInfo'; + readonly dbNum: Scalars['Int']['output']; + readonly id: Scalars['ID']['output']; + readonly name: Scalars['String']['output']; +}; + export { DbRole }; export type DeleteConfigurationResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { @@ -476,6 +483,7 @@ export type FundraisingAssignmentNode = Node & { readonly __typename?: 'FundraisingAssignmentNode'; readonly amount: Scalars['Float']['output']; readonly createdAt?: Maybe; + readonly entry: FundraisingEntryNode; readonly id: Scalars['ID']['output']; readonly person: PersonNode; readonly updatedAt?: Maybe; @@ -960,6 +968,7 @@ export type Mutation = { readonly addMap: MarathonHourNode; readonly addPersonToTeam: GetMembershipResponse; readonly assignEntryToPerson: FundraisingAssignmentNode; + readonly assignTeamToDbFundsTeam: Scalars['Void']['output']; readonly attachImageToFeedItem: FeedNode; readonly createConfiguration: CreateConfigurationResponse; readonly createConfigurations: CreateConfigurationResponse; @@ -1041,6 +1050,12 @@ export type MutationAssignEntryToPersonArgs = { }; +export type MutationAssignTeamToDbFundsTeamArgs = { + dbFundsTeamId: Scalars['Float']['input']; + teamId: Scalars['String']['input']; +}; + + export type MutationAttachImageToFeedItemArgs = { feedItemUuid: Scalars['String']['input']; imageUuid: Scalars['String']['input']; @@ -1428,11 +1443,12 @@ export { NumericComparator }; export type PersonNode = Node & { readonly __typename?: 'PersonNode'; - readonly assignedDonations?: Maybe; + readonly assignedDonationEntries?: Maybe; readonly committees: ReadonlyArray; readonly createdAt?: Maybe; readonly dbRole: DbRole; readonly email: Scalars['String']['output']; + readonly fundraisingAssignments: ReadonlyArray; readonly id: Scalars['ID']['output']; readonly linkblue?: Maybe; readonly moraleTeams: ReadonlyArray; @@ -1443,7 +1459,7 @@ export type PersonNode = Node & { }; -export type PersonNodeAssignedDonationsArgs = { +export type PersonNodeAssignedDonationEntriesArgs = { booleanFilters?: InputMaybe; dateFilters?: InputMaybe>; includeDeleted?: InputMaybe; @@ -1626,6 +1642,7 @@ export type Query = { readonly allConfigurations: GetAllConfigurationsResponse; readonly currentMarathon?: Maybe; readonly currentMarathonHour?: Maybe; + readonly dbFundsTeams: ReadonlyArray; readonly device: GetDeviceByUuidResponse; readonly devices: ListDevicesResponse; readonly event: GetEventByUuidResponse; @@ -1664,6 +1681,11 @@ export type QueryActiveConfigurationArgs = { }; +export type QueryDbFundsTeamsArgs = { + search: Scalars['String']['input']; +}; + + export type QueryDeviceArgs = { uuid: Scalars['String']['input']; }; diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 965a269d..9b7e8d20 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -196,9 +196,11 @@ export class FundraisingEntryRepository { ...where.dbFundsEntry, // @ts-expect-error Don't know why this is causing an error, but I'm not going to worry about it dbFundsTeam: { + teams: { + some: limits.forTeam, + }, // This 'satisfies' is to make sure that we don't accidentally ignore errors due to the ts-expect-error above - team: limits.forTeam satisfies Prisma.TeamWhereUniqueInput, - }, + } satisfies Prisma.DBFundsTeamWhereInput, }; } diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 1133d8ab..e079ca6d 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -142,7 +142,12 @@ export class PersonRepository { where: { person: param, team: { - type: TeamType.Committee, + correspondingCommittee: { + isNot: null, + }, + }, + committeeRole: { + not: null, }, }, select: { diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index d6f72b94..ef82d98b 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -30,7 +30,7 @@ export class LoginStateResolver { loginState(@Ctx() ctx: Context.GraphQLContext): LoginState { return { loggedIn: ctx.userData.authSource !== AuthSource.None, - effectiveCommitteeRoles: ctx.effectiveCommitteeRoles, + effectiveCommitteeRoles: ctx.authorization.committees, dbRole: ctx.authorization.dbRole, authSource: ctx.userData.authSource, }; diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 3d4556e9..7da9c64a 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -26,7 +26,6 @@ export const graphqlContextFunction: ContextFunction< // Set up the context object const context: GraphQLContext = { authenticatedUser: null, - effectiveCommitteeRoles: [], teamMemberships: [], userData: { authSource: AuthSource.None, @@ -129,7 +128,7 @@ export const graphqlContextFunction: ContextFunction< "graphqlContextFunction Effective committee roles", ...effectiveCommitteeRoles ); - context.effectiveCommitteeRoles = effectiveCommitteeRoles; + context.authorization.committees = effectiveCommitteeRoles; // If the user is on a committee, override the dbRole if (effectiveCommitteeRoles.length > 0) { diff --git a/schema.graphql b/schema.graphql index b3ef2cce..8bf709be 100644 --- a/schema.graphql +++ b/schema.graphql @@ -219,6 +219,12 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `dat """ scalar DateTimeISO +type DbFundsTeamInfo implements Node { + dbNum: Int! + id: ID! + name: String! +} + """DanceBlue roles""" enum DbRole { Committee @@ -348,7 +354,7 @@ enum DeviceResolverStringFilterKeys { } type EffectiveCommitteeRole { - committee: CommitteeIdentifier! + identifier: CommitteeIdentifier! role: CommitteeRole! } @@ -463,6 +469,7 @@ type FeedNode implements Node { type FundraisingAssignmentNode implements Node { amount: Float! createdAt: DateTimeISO + entry: FundraisingEntryNode! id: ID! person: PersonNode! updatedAt: DateTimeISO @@ -987,6 +994,7 @@ type Mutation { addMap(imageUuid: String!, uuid: String!): MarathonHourNode! addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! + assignTeamToDbFundsTeam(dbFundsTeamId: Float!, teamId: String!): Void! attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! createConfiguration(input: CreateConfigurationInput!): CreateConfigurationResponse! createConfigurations(input: [CreateConfigurationInput!]!): CreateConfigurationResponse! @@ -1228,7 +1236,7 @@ enum NumericComparator { } type PersonNode implements Node { - assignedDonations( + assignedDonationEntries( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1275,6 +1283,7 @@ type PersonNode implements Node { createdAt: DateTimeISO dbRole: DbRole! email: String! + fundraisingAssignments: [FundraisingAssignmentNode!]! id: ID! linkblue: String moraleTeams: [MembershipNode!]! @@ -1474,6 +1483,7 @@ type Query { allConfigurations: GetAllConfigurationsResponse! currentMarathon: MarathonNode currentMarathonHour: MarathonHourNode + dbFundsTeams(search: String!): [DbFundsTeamInfo!]! device(uuid: String!): GetDeviceByUuidResponse! devices( """The boolean filters to apply to the query""" From a55c337a38497fa0a67f7b606733be76485ab99e Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 16:30:10 +0000 Subject: [PATCH 104/153] Get fundraising tracking's core "finished" --- .../common/lib/authorization/accessControl.ts | 56 +++- .../common/lib/authorization/structures.ts | 6 +- .../common/lib/graphql-client-admin/gql.ts | 4 +- .../lib/graphql-client-admin/graphql.ts | 9 +- .../lib/graphql-client-public/graphql.ts | 5 +- packages/portal/src/hooks/useLoginState.ts | 4 +- .../migration.sql | 8 + .../migration.sql | 26 ++ packages/server/prisma/schema.prisma | 9 +- .../src/lib/fundraising/DbFundsProvider.ts | 4 +- .../fundraising/DBFundsRepository.ts | 170 ++++++++---- .../fundraising/FundraisingRepository.ts | 40 +-- .../repositories/person/PersonRepository.ts | 45 ++-- .../FundraisingAssignmentResolver.ts | 39 ++- .../src/resolvers/FundraisingEntryResolver.ts | 20 +- packages/server/src/resolvers/context.ts | 254 +++++++++++------- schema.graphql | 6 +- 17 files changed, 445 insertions(+), 260 deletions(-) create mode 100644 packages/server/prisma/migrations/20240613224347_unique_donated_by_to_on/migration.sql create mode 100644 packages/server/prisma/migrations/20240614023816_cascade_on_entry_delete/migration.sql diff --git a/packages/common/lib/authorization/accessControl.ts b/packages/common/lib/authorization/accessControl.ts index bc37d85d..e9256544 100644 --- a/packages/common/lib/authorization/accessControl.ts +++ b/packages/common/lib/authorization/accessControl.ts @@ -3,7 +3,6 @@ import { UseMiddleware } from "type-graphql"; import type { Primitive } from "utility-types"; import type { - AccessLevel, Authorization, CommitteeRole, DbRole, @@ -13,6 +12,7 @@ import type { UserData, } from "../index.js"; import { + AccessLevel, DetailedError, ErrorCode, compareCommitteeRole, @@ -189,7 +189,7 @@ interface ExtractorData { * 4. The root object matches ALL of the specified root matchers * 5. The custom authorization rule returns true */ -export interface AccessControlParam { +export interface AccessControlParam { authRules?: | readonly AuthorizationRule[] | ((root: RootType) => readonly AuthorizationRule[]); @@ -206,11 +206,16 @@ export interface AccessControlParam { * Custom authorization rule * * Should usually be avoided, but can be used for more complex authorization rules + * + * If the custom rule returns a boolean the user is allowed access if the rule returns true and an error is thrown if the rule returns false. + * If the custom rule returns null the field is set to null (make sure the field is nullable in the schema) + * If one param returns false and another returns null, an error will be thrown and the null ignored. */ custom?: ( root: RootType, - authorization: ExtractorData - ) => boolean | Promise; + context: ExtractorData, + result: ResultType + ) => boolean | null | Promise; } export interface SimpleTeamMembership { @@ -226,8 +231,11 @@ export interface AuthorizationContext { authorization: Authorization; } -export function AccessControl( - ...params: AccessControlParam[] +export function AccessControl< + RootType extends object = never, + ResultType extends object = never, +>( + ...params: AccessControlParam[] ): MethodDecorator & PropertyDecorator { const middleware: MiddlewareFn = async ( resolverData, @@ -237,6 +245,11 @@ export function AccessControl( const root = resolverData.root as RootType; const { authorization } = context; + if (authorization.accessLevel === AccessLevel.SuperAdmin) { + // Super admins have access to everything + return next(); + } + let ok = false; for (const rule of params) { @@ -342,25 +355,40 @@ export function AccessControl( } } + ok = true; + break; + } + + if (!ok) { + throw new DetailedError( + ErrorCode.Unauthorized, + "You are not authorized to access this resource." + ); + } + + const result = (await next()) as ResultType; + + let customResult: boolean | null = true; + for (const rule of params) { if (rule.custom != null) { // eslint-disable-next-line no-await-in-loop - if (!(await rule.custom(root, context))) { - continue; + customResult = await rule.custom(root, context, result); + if (customResult === true) { + break; } } - - ok = true; - break; } - if (!ok) { + if (customResult === false) { throw new DetailedError( ErrorCode.Unauthorized, "You are not authorized to access this resource." ); - } else { - return next(); + } else if (customResult === null) { + return null; } + + return result; }; return UseMiddleware(middleware); diff --git a/packages/common/lib/authorization/structures.ts b/packages/common/lib/authorization/structures.ts index dcd5acc4..dff5849b 100644 --- a/packages/common/lib/authorization/structures.ts +++ b/packages/common/lib/authorization/structures.ts @@ -79,10 +79,12 @@ export function stringifyAccessLevel(val: unknown): string { case AccessLevel.CommitteeChairOrCoordinator: { return "Committee Chair/Coordinator"; } - case AccessLevel.Admin: - case AccessLevel.SuperAdmin: { + case AccessLevel.Admin: { return "Admin"; } + case AccessLevel.SuperAdmin: { + return "God Emperor of DanceBlue"; + } } } diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 8f6143de..dc069d95 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -49,7 +49,7 @@ const documents = { "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n": types.PersonViewerFragmentFragmentDoc, "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, - "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n": types.LoginStateDocument, + "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n identifier\n }\n }\n }\n": types.LoginStateDocument, "\n mutation CommitConfigChanges($changes: [CreateConfigurationInput!]!) {\n createConfigurations(input: $changes) {\n ok\n }\n }\n": types.CommitConfigChangesDocument, "\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n": types.ConfigFragmentFragmentDoc, "\n query ConfigQuery {\n allConfigurations {\n data {\n ...ConfigFragment\n }\n }\n }\n ": types.ConfigQueryDocument, @@ -248,7 +248,7 @@ export function graphql(source: "\n fragment TeamViewerFragment on TeamNode {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n committee\n }\n }\n }\n"]; +export function graphql(source: "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n identifier\n }\n }\n }\n"): (typeof documents)["\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n identifier\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 122a6f8d..a20206e6 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -380,7 +380,7 @@ export const DeviceResolverStringFilterKeys = { export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; export type EffectiveCommitteeRole = { readonly __typename?: 'EffectiveCommitteeRole'; - readonly committee: CommitteeIdentifier; + readonly identifier: CommitteeIdentifier; readonly role: CommitteeRole; }; @@ -485,7 +485,8 @@ export type FundraisingAssignmentNode = Node & { readonly createdAt?: Maybe; readonly entry: FundraisingEntryNode; readonly id: Scalars['ID']['output']; - readonly person: PersonNode; + /** The person assigned to this assignment, only null when access is denied */ + readonly person?: Maybe; readonly updatedAt?: Maybe; }; @@ -2398,7 +2399,7 @@ export type TeamViewerFragmentFragment = { readonly __typename?: 'TeamNode', rea export type LoginStateQueryVariables = Exact<{ [key: string]: never; }>; -export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly dbRole: DbRole, readonly effectiveCommitteeRoles: ReadonlyArray<{ readonly __typename?: 'EffectiveCommitteeRole', readonly role: CommitteeRole, readonly committee: CommitteeIdentifier }> } }; +export type LoginStateQuery = { readonly __typename?: 'Query', readonly loginState: { readonly __typename?: 'LoginState', readonly loggedIn: boolean, readonly dbRole: DbRole, readonly effectiveCommitteeRoles: ReadonlyArray<{ readonly __typename?: 'EffectiveCommitteeRole', readonly role: CommitteeRole, readonly identifier: CommitteeIdentifier }> } }; export type CommitConfigChangesMutationVariables = Exact<{ changes: ReadonlyArray | CreateConfigurationInput; @@ -2718,7 +2719,7 @@ export const NotificationsTableQueryDocument = {"kind":"Document","definitions": export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"effectiveCommitteeRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"committee"}}]}}]}}]}}]} as unknown as DocumentNode; +export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"effectiveCommitteeRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identifier"}}]}}]}}]}}]} as unknown as DocumentNode; export const CommitConfigChangesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitConfigChanges"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"changes"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateConfigurationInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createConfigurations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"changes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const ConfigQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ConfigQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allConfigurations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ConfigFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const CreateEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index ef77d236..2112510d 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -380,7 +380,7 @@ export const DeviceResolverStringFilterKeys = { export type DeviceResolverStringFilterKeys = typeof DeviceResolverStringFilterKeys[keyof typeof DeviceResolverStringFilterKeys]; export type EffectiveCommitteeRole = { readonly __typename?: 'EffectiveCommitteeRole'; - readonly committee: CommitteeIdentifier; + readonly identifier: CommitteeIdentifier; readonly role: CommitteeRole; }; @@ -485,7 +485,8 @@ export type FundraisingAssignmentNode = Node & { readonly createdAt?: Maybe; readonly entry: FundraisingEntryNode; readonly id: Scalars['ID']['output']; - readonly person: PersonNode; + /** The person assigned to this assignment, only null when access is denied */ + readonly person?: Maybe; readonly updatedAt?: Maybe; }; diff --git a/packages/portal/src/hooks/useLoginState.ts b/packages/portal/src/hooks/useLoginState.ts index 4734d3c2..164e152c 100644 --- a/packages/portal/src/hooks/useLoginState.ts +++ b/packages/portal/src/hooks/useLoginState.ts @@ -10,7 +10,7 @@ const loginStateDocument = graphql(/* GraphQL */ ` dbRole effectiveCommitteeRoles { role - committee + identifier } } } @@ -40,7 +40,7 @@ export function useLoginState(): { } const committees = data.loginState.effectiveCommitteeRoles.map( - ({ committee, role }) => ({ identifier: committee, role }) + ({ identifier, role }) => ({ identifier, role }) ); return { diff --git a/packages/server/prisma/migrations/20240613224347_unique_donated_by_to_on/migration.sql b/packages/server/prisma/migrations/20240613224347_unique_donated_by_to_on/migration.sql new file mode 100644 index 00000000..5f05f476 --- /dev/null +++ b/packages/server/prisma/migrations/20240613224347_unique_donated_by_to_on/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[donated_to,donated_by,date]` on the table `db_funds_team_entries` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "db_funds_team_entries_donated_to_donated_by_date_key" ON "db_funds_team_entries"("donated_to", "donated_by", "date"); diff --git a/packages/server/prisma/migrations/20240614023816_cascade_on_entry_delete/migration.sql b/packages/server/prisma/migrations/20240614023816_cascade_on_entry_delete/migration.sql new file mode 100644 index 00000000..7f2b0e5e --- /dev/null +++ b/packages/server/prisma/migrations/20240614023816_cascade_on_entry_delete/migration.sql @@ -0,0 +1,26 @@ +/* + Warnings: + + - Made the column `db_funds_entry_id` on table `fundraising_entries` required. This step will fail if there are existing NULL values in that column. + +*/ +-- DropForeignKey +ALTER TABLE "fundraising_assignments" DROP CONSTRAINT "fundraising_assignments_fundraising_id_fkey"; + +-- DropForeignKey +ALTER TABLE "fundraising_assignments" DROP CONSTRAINT "fundraising_assignments_person_id_fkey"; + +-- DropForeignKey +ALTER TABLE "fundraising_entries" DROP CONSTRAINT "fundraising_entries_db_funds_entry_id_fkey"; + +-- AlterTable +ALTER TABLE "fundraising_entries" ALTER COLUMN "db_funds_entry_id" SET NOT NULL; + +-- AddForeignKey +ALTER TABLE "fundraising_entries" ADD CONSTRAINT "fundraising_entries_db_funds_entry_id_fkey" FOREIGN KEY ("db_funds_entry_id") REFERENCES "db_funds_team_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "fundraising_assignments" ADD CONSTRAINT "fundraising_assignments_person_id_fkey" FOREIGN KEY ("person_id") REFERENCES "people"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "fundraising_assignments" ADD CONSTRAINT "fundraising_assignments_fundraising_id_fkey" FOREIGN KEY ("fundraising_id") REFERENCES "fundraising_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 01e16618..4dc09283 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -447,6 +447,7 @@ model DBFundsFundraisingEntry { // The corresponding fundraising entry in our database fundraisingEntry FundraisingEntry? + @@unique([donatedTo, donatedBy, date]) @@map("db_funds_team_entries") } @@ -456,8 +457,8 @@ model FundraisingEntry { createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) - dbFundsEntry DBFundsFundraisingEntry? @relation(fields: [dbFundsEntryId], references: [id], onDelete: SetNull) - dbFundsEntryId Int? @unique @map("db_funds_entry_id") + dbFundsEntry DBFundsFundraisingEntry @relation(fields: [dbFundsEntryId], references: [id], onDelete: Cascade) + dbFundsEntryId Int @unique @map("db_funds_entry_id") assignments FundraisingAssignment[] @@ -472,8 +473,8 @@ model FundraisingAssignment { updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(6) amount Decimal personId Int @map("person_id") - person Person @relation(fields: [personId], references: [id]) - parentEntry FundraisingEntry @relation(fields: [fundraisingId], references: [id]) + person Person @relation(fields: [personId], references: [id], onDelete: Cascade) + parentEntry FundraisingEntry @relation(fields: [fundraisingId], references: [id], onDelete: Cascade) fundraisingId Int @map("fundraising_id") @@unique([fundraisingId, personId], map: "fundraising_assignments_fundraising_id_person_id_key") diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 65e24911..1038238f 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -49,12 +49,12 @@ const dbFundsFundraisingEntrySchema = z.object({ donatedBy: z .string() .describe("The name of the person who donated") - .transform((v) => (isNA.test(v) ? null : v)) + .transform((v) => (isNA.test(v) || v.length === 0 ? null : v)) .nullable(), donatedTo: z .string() .describe("The name of the person or team who received the donation") - .transform((v) => (isNA.test(v) ? null : v)) + .transform((v) => (isNA.test(v) || v.length === 0 ? null : v)) .nullable(), donatedOn: z .string() diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 20d3f5ef..d6add06d 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,4 +1,4 @@ -import { DBFundsTeam, PrismaClient, Team } from "@prisma/client"; +import { DBFundsTeam, Prisma, PrismaClient, Team } from "@prisma/client"; import { DateTime } from "luxon"; import { Maybe, Result, Unit } from "true-myth"; import { err, ok } from "true-myth/result"; @@ -12,12 +12,11 @@ import { SomePrismaError, toPrismaError, } from "../../lib/error/prisma.js"; +import { logger } from "../../lib/logging/standardLogging.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { SimpleUniqueParam } from "../shared.js"; -import { FundraisingEntryRepository } from "./FundraisingRepository.js"; - export type UniqueDbFundsTeamParam = | { id: number; @@ -31,8 +30,7 @@ export type UniqueDbFundsTeamParam = export class DBFundsRepository { constructor( private readonly prisma: PrismaClient, - private readonly marathonRepository: MarathonRepository, - private readonly fundraisingEntryRepository: FundraisingEntryRepository + private readonly marathonRepository: MarathonRepository ) {} async overwriteTeamForFiscalYear( @@ -43,7 +41,7 @@ export class DBFundsRepository { name: string; }, marathonParam: UniqueMarathonParam, - entries: { + dbFundsEntries: { donatedBy: Maybe; donatedTo: Maybe; donatedOn: DateTime; @@ -70,73 +68,129 @@ export class DBFundsRepository { } marathonId = marathon.id; } - const rows = await this.prisma.dBFundsTeam.upsert({ + + let dBFundsTeam = await this.prisma.dBFundsTeam.findUnique({ where: { dbNum_marathonId: { dbNum: team.dbNum, marathonId, }, }, - create: { - dbNum: team.dbNum, - totalAmount: team.total, - active: team.active, - name: team.name, - marathon: { - connect: { id: marathonId }, - }, - fundraisingEntries: { - create: entries.map((entry) => ({ - donatedBy: entry.donatedBy.unwrapOr(null), - donatedTo: entry.donatedTo.unwrapOr(null), - date: entry.donatedOn.toJSDate(), - amount: entry.amount, - })), - }, - }, - update: { - totalAmount: team.total, - name: team.name, - active: team.active, - fundraisingEntries: { - // This deletes all existing entries, including ones from past years. This is intentional as it means we aren't persisting sensitive data that we won't be using anyways - // If it ever becomes desired to keep this data, simple filter the delete to only entries from the current marathon - deleteMany: {}, - create: entries.map((entry) => ({ - donatedBy: entry.donatedBy.unwrapOr(null), - donatedTo: entry.donatedTo.unwrapOr(null), - date: entry.donatedOn.toJSDate(), - amount: entry.amount, - })), - }, - }, - select: { + include: { fundraisingEntries: true, }, }); - const results = await Promise.allSettled( - rows.fundraisingEntries.map(async (entry) => { - return this.fundraisingEntryRepository.connectEntry(entry); - }) + if (!dBFundsTeam) { + dBFundsTeam = await this.prisma.dBFundsTeam.create({ + data: { + dbNum: team.dbNum, + totalAmount: team.total, + active: team.active, + name: team.name, + marathon: { + connect: { id: marathonId }, + }, + }, + include: { + fundraisingEntries: true, + }, + }); + } + + const entriesToCreate: Prisma.DBFundsFundraisingEntryCreateWithoutDbFundsTeamInput[] = + []; + const entriesToUpdate: { + amount: number; + id: number; + }[] = []; + + // Unlike the other lists, this one is removed from rather than added to + const entryIdsToDelete: Set = new Set( + dBFundsTeam.fundraisingEntries.map((entry) => entry.id) ); - const errors: (PrismaError | BasicError)[] = []; - for (const result of results) { - if (result.status === "rejected") { - errors.push( - toPrismaError(result.reason).unwrapOrElse(() => - toBasicError(result.reason) - ) - ); - } else if (result.value.isErr) { - errors.push(result.value.error); + for (const entry of dbFundsEntries) { + const entryDonatedOnMillis = entry.donatedOn.toMillis(); + const existingEntry = dBFundsTeam.fundraisingEntries.find( + (e) => + e.donatedBy === entry.donatedBy.unwrapOr(null) && + e.donatedTo === entry.donatedTo.unwrapOr(null) && + e.date.getTime() === entryDonatedOnMillis + ); + + if (!existingEntry) { + entriesToCreate.push({ + donatedBy: entry.donatedBy.unwrapOr(null), + donatedTo: entry.donatedTo.unwrapOr(null), + date: entry.donatedOn.toJSDate(), + amount: entry.amount, + fundraisingEntry: { + create: {}, + }, + }); + } else { + entryIdsToDelete.delete(existingEntry.id); + if (existingEntry.amount.toNumber() !== entry.amount) { + entriesToUpdate.push({ + amount: entry.amount, + id: existingEntry.id, + }); + } } } - return errors.length > 0 - ? Result.err(new CompositeError(errors)) - : Result.ok(); + if ( + entriesToCreate.length > 0 || + entriesToUpdate.length > 0 || + entryIdsToDelete.size > 0 + ) { + logger.debug(`Fundraising Sync`, { + team: { name: team.name, dbNum: team.dbNum }, + entries: { + toCreate: entriesToCreate.length, + toUpdate: entriesToUpdate.length, + toDelete: entryIdsToDelete.size, + }, + }); + + await this.prisma.dBFundsTeam.update({ + where: { + id: dBFundsTeam.id, + }, + data: { + fundraisingEntries: { + deleteMany: { + id: { + in: [...entryIdsToDelete], + }, + }, + create: entriesToCreate, + update: entriesToUpdate.map(({ amount, id }) => ({ + where: { id }, + data: { + amount, + fundraisingEntry: { + upsert: { + update: { + assignments: { + deleteMany: {}, + }, + }, + create: {}, + }, + }, + }, + })), + }, + }, + include: { + fundraisingEntries: true, + }, + }); + } + + return Result.ok(); } catch (error) { return Result.err( toPrismaError(error).unwrapOrElse(() => toBasicError(error)) diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 9b7e8d20..54d01a06 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -88,10 +88,8 @@ export class FundraisingEntryRepository { where: param, include: defaultInclude, }); - if (!row?.dbFundsEntry) { - return err( - new NotFoundError({ what: "FundraisingEntry.dbFundsEntry" }) - ); + if (!row) { + return err(new NotFoundError({ what: "FundraisingEntry" })); } return ok( row as typeof row & { @@ -247,29 +245,6 @@ export class FundraisingEntryRepository { } } - async connectEntry( - dbFundsEntry: DBFundsFundraisingEntry - ): Promise< - Result - > { - try { - const row = await this.prisma.fundraisingEntry.upsert({ - where: { id: dbFundsEntry.id }, - update: {}, - create: { - dbFundsEntry: { - connect: { id: dbFundsEntry.id }, - }, - }, - }); - return ok({ - id: row.id, - }); - } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); - } - } - async deleteEntry( param: FundraisingEntryUniqueParam ): Promise, SomePrismaError | BasicError>> { @@ -380,12 +355,6 @@ export class FundraisingEntryRepository { return err(assignments.error); } - if (!assignment.parentEntry.dbFundsEntry) { - return err( - new ActionDeniedError("Entry is not connected to a DBFunds entry") - ); - } - const totalAssigned = assignments.value .filter((a) => a.id !== assignment.id) .reduce( @@ -452,11 +421,6 @@ export class FundraisingEntryRepository { if (!assignment) { return err(new NotFoundError({ what: "FundraisingAssignment" })); } - if (!assignment.parentEntry.dbFundsEntry) { - return err( - new NotFoundError({ what: "FundraisingEntry.dbFundsEntry" }) - ); - } return ok( assignment.parentEntry as typeof assignment.parentEntry & { dbFundsEntry: NonNullable; diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index e079ca6d..e64fcc2a 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -300,32 +300,31 @@ export class PersonRepository { types: TeamType[] | undefined = undefined, includeTeam: boolean = false ) { - const rows = await this.prisma.person.findUnique({ - where: param, - select: { - memberships: { - include: { - team: includeTeam, - }, - where: { - AND: [ - opts, - types - ? { - team: { - type: { - in: types, - }, + const rows = await this.prisma.person + .findUnique({ + where: param, + }) + .memberships({ + include: { + team: includeTeam, + }, + where: { + AND: [ + opts, + types + ? { + team: { + type: { + in: types, }, - } - : {}, - ], - }, + }, + } + : {}, + ], }, - }, - }); + }); - return rows?.memberships ?? null; + return rows ?? null; } // Mutators diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index c95fadd1..51fff068 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -5,6 +5,7 @@ import { CommitteeRole, FundraisingAssignmentNode, FundraisingEntryNode, + MembershipPositionType, PersonNode, } from "@ukdanceblue/common"; import { @@ -17,7 +18,7 @@ import { Resolver, Root, } from "type-graphql"; -import { Service } from "typedi"; +import { Container, Service } from "typedi"; import { CatchableConcreteError } from "../lib/formatError.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; @@ -26,6 +27,8 @@ import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundrai import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; +import { globalFundraisingAccessParam } from "./FundraisingEntryResolver.js"; + @InputType() class AssignEntryToPersonInput { @Field() @@ -127,9 +130,37 @@ export class FundraisingAssignmentResolver { return fundraisingAssignmentModelToNode(assignment.value); } - // I'm fairly certain this is safe to leave without an access control check as anyone with - // access to the assignment should have access to the person - @FieldResolver(() => PersonNode) + @AccessControl(globalFundraisingAccessParam, { + custom: async (_, { teamMemberships }, { id }) => { + const personRepository = Container.get(PersonRepository); + const memberships = + (await personRepository.findMembershipsOfPerson( + { uuid: id }, + undefined, + undefined, + true + )) ?? []; + const userCaptaincies = teamMemberships.filter( + (membership) => membership.position === MembershipPositionType.Captain + ); + for (const targetPersonMembership of memberships) { + if ( + userCaptaincies.some( + (userCaptaincy) => + userCaptaincy.teamId === targetPersonMembership.team.uuid + ) + ) { + return true; + } + } + return null; + }, + }) + @FieldResolver(() => PersonNode, { + nullable: true, + description: + "The person assigned to this assignment, only null when access is denied", + }) async person( @Root() assignment: FundraisingAssignmentNode ): Promise { diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index e05bab1d..0248a121 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -70,15 +70,17 @@ export class ListFundraisingEntriesResponse extends AbstractGraphQLPaginatedResp /** * Access control param for granting access to all fundraising entries. */ -export const globalFundraisingAccessParam: AccessControlParam = - { - authRules: [ - { - minCommitteeRole: CommitteeRole.Coordinator, - committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], - }, - ], - }; +export const globalFundraisingAccessParam: AccessControlParam< + unknown, + unknown +> = { + authRules: [ + { + minCommitteeRole: CommitteeRole.Coordinator, + committeeIdentifiers: [CommitteeIdentifier.fundraisingCommittee], + }, + ], +}; @Resolver(() => FundraisingEntryNode) @Service() diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 7da9c64a..d2fd7dc6 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -1,8 +1,13 @@ import type { ContextFunction } from "@apollo/server"; import type { KoaContextFunctionArgument } from "@as-integrations/koa"; -import type { AuthorizationContext } from "@ukdanceblue/common"; +import type { + AuthorizationContext, + EffectiveCommitteeRole, +} from "@ukdanceblue/common"; import { + AccessLevel, AuthSource, + CommitteeIdentifier, CommitteeRole, DbRole, roleToAccessLevel, @@ -19,21 +24,113 @@ export interface GraphQLContext extends AuthorizationContext { contextErrors: string[]; } +function isSuperAdmin(committeeRoles: EffectiveCommitteeRole[]): boolean { + return committeeRoles.some( + (role) => + // TODO: replace "=== Coordinator" with a check for just app&web, but that requires information about what kind of coordinator someone is + role.identifier === CommitteeIdentifier.techCommittee && + (role.role === CommitteeRole.Chair || + role.role === CommitteeRole.Coordinator) + ); +} + +async function withUserInfo( + inputContext: GraphQLContext, + userId: string +): Promise { + const outputContext = structuredClone(inputContext); + const personRepository = Container.get(PersonRepository); + const person = await personRepository.findPersonAndTeamsByUnique({ + uuid: userId, + }); + + // If we found a user, set the authenticated user + if (person) { + // Convert the user to a resource and set it on the context + const personResource = await personModelToResource( + person, + personRepository + ); + logger.trace("graphqlContextFunction Found user", personResource); + outputContext.authenticatedUser = personResource; + outputContext.userData.userId = userId; + + // Set the committees the user is on + const committeeMemberships = + await personRepository.findCommitteeMembershipsOfPerson({ + id: person.id, + }); + const committees = + committeeMemberships + ?.map((membership) => + membership.team.correspondingCommittee + ? { + identifier: membership.team.correspondingCommittee.identifier, + role: membership.committeeRole ?? CommitteeRole.Member, + } + : undefined + ) + .filter( + (committee): committee is NonNullable => + committee != null + ) ?? []; + logger.trace("graphqlContextFunction Found committees", ...committees); + outputContext.authorization.committees = committees; + + // Set the teams the user is on + const teamMemberships = + (await personRepository.findMembershipsOfPerson( + { + id: person.id, + }, + {}, + undefined, + true + )) ?? []; + logger.trace( + "graphqlContextFunction Found team memberships", + ...teamMemberships + ); + outputContext.teamMemberships = teamMemberships.map((membership) => ({ + teamType: membership.team.type, + position: membership.position, + teamId: membership.team.uuid, + })); + + // Set the effective committee roles the user has + const effectiveCommitteeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ + id: person.id, + }); + logger.trace( + "graphqlContextFunction Effective committee roles", + ...effectiveCommitteeRoles + ); + outputContext.authorization.committees = effectiveCommitteeRoles; + + // If the user is on a committee, override the dbRole + if (effectiveCommitteeRoles.length > 0) { + outputContext.authorization.dbRole = DbRole.Committee; + } + } + + return outputContext; +} + +const defaultContext: Readonly = Object.freeze({ + authenticatedUser: null, + teamMemberships: [], + userData: { + authSource: AuthSource.None, + }, + authorization: defaultAuthorization, + contextErrors: [], +}); + export const graphqlContextFunction: ContextFunction< [KoaContextFunctionArgument], GraphQLContext > = async ({ ctx }): Promise => { - // Set up the context object - const context: GraphQLContext = { - authenticatedUser: null, - teamMemberships: [], - userData: { - authSource: AuthSource.None, - }, - authorization: defaultAuthorization, - contextErrors: [], - }; - // Get the token from the cookies or the Authorization header let token = ctx.cookies.get("token"); if (!token) { @@ -44,102 +141,69 @@ export const graphqlContextFunction: ContextFunction< } if (!token) { // Short-circuit if no token is present - return context; + return defaultContext; } // Parse the token const { userId, authSource } = parseUserJwt(token); - // Set the auth source - context.userData.authSource = authSource; // Set the dbRole based on the auth source + let authSourceDbRole: DbRole; if (authSource === AuthSource.LinkBlue || authSource === AuthSource.Demo) { - context.authorization.dbRole = DbRole.UKY; + authSourceDbRole = DbRole.UKY; } else if (authSource === AuthSource.Anonymous) { - context.authorization.dbRole = DbRole.Public; + authSourceDbRole = DbRole.Public; + } else { + authSourceDbRole = DbRole.None; + } + + if (!userId) { + logger.trace("graphqlContextFunction No user ID"); + return structuredClone(defaultContext); } // If we have a user ID, look up the user - if (userId) { - const personRepository = Container.get(PersonRepository); - const person = await personRepository.findPersonAndTeamsByUnique({ - uuid: userId, - }); - - // If we found a user, set the authenticated user - if (person) { - // Convert the user to a resource and set it on the context - const personResource = await personModelToResource( - person, - personRepository - ); - logger.trace("graphqlContextFunction Found user", personResource); - context.authenticatedUser = personResource; - context.userData.userId = userId; - - // Set the committees the user is on - const committeeMemberships = - await personRepository.findCommitteeMembershipsOfPerson({ - id: person.id, - }); - const committees = - committeeMemberships - ?.map((membership) => - membership.team.correspondingCommittee - ? { - identifier: membership.team.correspondingCommittee.identifier, - role: membership.committeeRole ?? CommitteeRole.Member, - } - : undefined - ) - .filter( - (committee): committee is NonNullable => - committee != null - ) ?? []; - logger.trace("graphqlContextFunction Found committees", ...committees); - context.authorization.committees = committees; - - // Set the teams the user is on - const teamMemberships = - (await personRepository.findMembershipsOfPerson( - { - id: person.id, - }, - {}, - undefined, - true - )) ?? []; - logger.trace( - "graphqlContextFunction Found team memberships", - ...teamMemberships - ); - context.teamMemberships = teamMemberships.map((membership) => ({ - teamType: membership.team.type, - position: membership.position, - teamId: membership.team.uuid, - })); - - // Set the effective committee roles the user has - const effectiveCommitteeRoles = - await personRepository.getEffectiveCommitteeRolesOfPerson({ - id: person.id, - }); - logger.trace( - "graphqlContextFunction Effective committee roles", - ...effectiveCommitteeRoles - ); - context.authorization.committees = effectiveCommitteeRoles; - - // If the user is on a committee, override the dbRole - if (effectiveCommitteeRoles.length > 0) { - context.authorization.dbRole = DbRole.Committee; - } - } + let contextWithUser = await withUserInfo( + { + ...defaultContext, + authorization: { + ...defaultContext.authorization, + dbRole: authSourceDbRole, + }, + }, + userId + ); + let superAdmin = isSuperAdmin(contextWithUser.authorization.committees); + if ( + superAdmin && + ctx.request.headers["x-ukdb-masquerade"] && + typeof ctx.request.headers["x-ukdb-masquerade"] === "string" + ) { + // We need to reset the dbRole to the default one in case the masquerade user is not a committee member + contextWithUser = await withUserInfo( + { + ...defaultContext, + authorization: { + ...defaultContext.authorization, + dbRole: authSourceDbRole, + }, + }, + ctx.request.headers["x-ukdb-masquerade"] + ); + superAdmin = false; } - context.authorization.accessLevel = roleToAccessLevel(context.authorization); + const finalContext: GraphQLContext = { + ...contextWithUser, + authorization: { + ...contextWithUser.authorization, + accessLevel: superAdmin + ? AccessLevel.SuperAdmin + : roleToAccessLevel(contextWithUser.authorization), + }, + }; - logger.trace("graphqlContextFunction Context", context); + logger.trace("graphqlContextFunction Context", finalContext); - return context; + return finalContext; }; diff --git a/schema.graphql b/schema.graphql index 8bf709be..9caceb00 100644 --- a/schema.graphql +++ b/schema.graphql @@ -471,7 +471,11 @@ type FundraisingAssignmentNode implements Node { createdAt: DateTimeISO entry: FundraisingEntryNode! id: ID! - person: PersonNode! + + """ + The person assigned to this assignment, only null when access is denied + """ + person: PersonNode updatedAt: DateTimeISO } From 059098068ee9bc4690d05ed69ebdd041ef00229d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 16:50:44 +0000 Subject: [PATCH 105/153] Simplify results use in resolvers --- packages/server/src/lib/error/result.ts | 5 +- packages/server/src/lib/graphqlSchema.ts | 24 ++++++++- .../FundraisingAssignmentResolver.ts | 50 ++++++------------- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/packages/server/src/lib/error/result.ts b/packages/server/src/lib/error/result.ts index fa6bc2d5..987b1cc6 100644 --- a/packages/server/src/lib/error/result.ts +++ b/packages/server/src/lib/error/result.ts @@ -12,7 +12,10 @@ export type ConcreteErrorTypes = | PrismaError | ZodError; -export type ConcreteResult = Result; +export type ConcreteResult = Result< + T, + E +>; export type JsResult = ConcreteResult< T, diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index dc5efb55..b816f2d3 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -1,5 +1,6 @@ import { fileURLToPath } from "url"; +import { isInstance } from "true-myth/result"; import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; @@ -24,19 +25,40 @@ import { PointEntryResolver } from "../resolvers/PointEntryResolver.js"; import { PointOpportunityResolver } from "../resolvers/PointOpportunityResolver.js"; import { TeamResolver } from "../resolvers/TeamResolver.js"; +import { ConcreteError, toBasicError } from "./error/error.js"; +import { CatchableConcreteError } from "./formatError.js"; import { logger } from "./logging/logger.js"; const schemaPath = fileURLToPath( new URL("../../../../schema.graphql", import.meta.url) ); +/** + * Logs errors, as well as allowing us to return a result from a resolver + */ const errorHandlingMiddleware: MiddlewareFn = async (_, next) => { + let result; try { - return void (await next()); + result = (await next()) as unknown; } catch (error) { logger.error("An error occurred in a resolver", error); throw error; } + + if (isInstance(result)) { + if (result.isErr) { + logger.error("An error occurred in a resolver", result.error); + throw new CatchableConcreteError( + result.error instanceof ConcreteError + ? result.error + : toBasicError(result.error) + ); + } else { + return result.value; + } + } else { + return result; + } }; const resolvers = [ diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 51fff068..370c3644 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -20,7 +20,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { CatchableConcreteError } from "../lib/formatError.js"; +import { ConcreteResult } from "../lib/error/result.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; @@ -62,17 +62,13 @@ export class FundraisingAssignmentResolver { @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( @Arg("id") id: string - ): Promise { + ): Promise>> { const assignment = await this.fundraisingEntryRepository.findAssignmentByUnique({ uuid: id, }); - if (assignment.isErr) { - throw new CatchableConcreteError(assignment.error); - } - - return fundraisingAssignmentModelToNode(assignment.value); + return assignment.map(fundraisingAssignmentModelToNode); } @AccessControl(fundraisingAccess) @@ -81,7 +77,7 @@ export class FundraisingAssignmentResolver { @Arg("entryId") entryId: string, @Arg("personId") personId: string, @Arg("input") { amount }: AssignEntryToPersonInput - ): Promise { + ): Promise>> { const assignment = await this.fundraisingEntryRepository.addAssignmentToEntry( { uuid: entryId }, @@ -89,11 +85,7 @@ export class FundraisingAssignmentResolver { { amount } ); - if (assignment.isErr) { - throw new CatchableConcreteError(assignment.error); - } - - return fundraisingAssignmentModelToNode(assignment.value); + return assignment.map(fundraisingAssignmentModelToNode); } @AccessControl(fundraisingAccess) @@ -101,33 +93,25 @@ export class FundraisingAssignmentResolver { async updateFundraisingAssignment( @Arg("id") id: string, @Arg("input") { amount }: UpdateFundraisingAssignmentInput - ): Promise { + ): Promise>> { const assignment = await this.fundraisingEntryRepository.updateAssignment( { uuid: id }, { amount } ); - if (assignment.isErr) { - throw new CatchableConcreteError(assignment.error); - } - - return fundraisingAssignmentModelToNode(assignment.value); + return assignment.map(fundraisingAssignmentModelToNode); } @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async deleteFundraisingAssignment( @Arg("id") id: string - ): Promise { + ): Promise>> { const assignment = await this.fundraisingEntryRepository.deleteAssignment({ uuid: id, }); - if (assignment.isErr) { - throw new CatchableConcreteError(assignment.error); - } - - return fundraisingAssignmentModelToNode(assignment.value); + return assignment.map(fundraisingAssignmentModelToNode); } @AccessControl(globalFundraisingAccessParam, { @@ -163,26 +147,22 @@ export class FundraisingAssignmentResolver { }) async person( @Root() assignment: FundraisingAssignmentNode - ): Promise { + ): Promise>> { const person = await this.fundraisingEntryRepository.getPersonForAssignment( { uuid: assignment.id } ); - if (person.isErr) { - throw new CatchableConcreteError(person.error); - } - return personModelToResource(person.value, this.personRepository); + return person.map((person) => + personModelToResource(person, this.personRepository) + ); } @FieldResolver(() => FundraisingEntryNode) async entry( @Root() assignment: FundraisingAssignmentNode - ): Promise { + ): Promise>> { const entry = await this.fundraisingEntryRepository.getEntryForAssignment({ uuid: assignment.id, }); - if (entry.isErr) { - throw new CatchableConcreteError(entry.error); - } - return fundraisingEntryModelToNode(entry.value); + return entry.map(fundraisingEntryModelToNode); } } From 3c2688268f192b83f5cdf8befc121139514d21c2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 19:23:54 +0000 Subject: [PATCH 106/153] feat: Add assignTeamToDbFundsTeam mutation --- packages/server/src/resolvers/context.ts | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index d2fd7dc6..8399ac0a 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -56,24 +56,14 @@ async function withUserInfo( outputContext.userData.userId = userId; // Set the committees the user is on - const committeeMemberships = - await personRepository.findCommitteeMembershipsOfPerson({ + const committeeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ id: person.id, }); - const committees = - committeeMemberships - ?.map((membership) => - membership.team.correspondingCommittee - ? { - identifier: membership.team.correspondingCommittee.identifier, - role: membership.committeeRole ?? CommitteeRole.Member, - } - : undefined - ) - .filter( - (committee): committee is NonNullable => - committee != null - ) ?? []; + const committees = committeeRoles.map(({ committee, role }) => ({ + identifier: committee, + role, + })); logger.trace("graphqlContextFunction Found committees", ...committees); outputContext.authorization.committees = committees; @@ -106,7 +96,7 @@ async function withUserInfo( "graphqlContextFunction Effective committee roles", ...effectiveCommitteeRoles ); - outputContext.authorization.committees = effectiveCommitteeRoles; + outputContext.authorization.committees = effectiveCommitteeRoles.map(({committee,role}) => ({identifier: committee, role})) // If the user is on a committee, override the dbRole if (effectiveCommitteeRoles.length > 0) { From b5a33a9f55b874b19ff2546b82a0ad0a0897c225 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 19:31:19 +0000 Subject: [PATCH 107/153] Fix fields on committee roles --- packages/server/src/resolvers/context.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 8399ac0a..122bc6f5 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -60,10 +60,7 @@ async function withUserInfo( await personRepository.getEffectiveCommitteeRolesOfPerson({ id: person.id, }); - const committees = committeeRoles.map(({ committee, role }) => ({ - identifier: committee, - role, - })); + const committees = committeeRoles; logger.trace("graphqlContextFunction Found committees", ...committees); outputContext.authorization.committees = committees; @@ -96,7 +93,7 @@ async function withUserInfo( "graphqlContextFunction Effective committee roles", ...effectiveCommitteeRoles ); - outputContext.authorization.committees = effectiveCommitteeRoles.map(({committee,role}) => ({identifier: committee, role})) + outputContext.authorization.committees = effectiveCommitteeRoles; // If the user is on a committee, override the dbRole if (effectiveCommitteeRoles.length > 0) { From fbfc2cc61bea33e66d2a62a536fd7ae175469411 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 19:32:10 +0000 Subject: [PATCH 108/153] Update fundraising repository to check parent entry funds amount --- .../server/src/repositories/fundraising/FundraisingRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 54d01a06..5ba8a9ad 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -362,6 +362,7 @@ export class FundraisingEntryRepository { new Prisma.Decimal(0) ); if ( + assignment.parentEntry.dbFundsEntry && assignment.parentEntry.dbFundsEntry.amount.lessThan( totalAssigned.add(amount) ) From 9374a4efc03a6617c850fe8d4769790ed2d44934 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 14 Jun 2024 21:55:45 +0000 Subject: [PATCH 109/153] Start getting marathon selection on portal --- eslint/base.ts | 10 +- eslint/out/base.js | 10 +- .../common/lib/graphql-client-admin/gql.ts | 14 +- .../lib/graphql-client-admin/graphql.ts | 20 +- .../common/lib/graphql-client-public/gql.ts | 8 +- .../lib/graphql-client-public/graphql.ts | 10 +- .../src/common/hooks/useMarathonTime.ts | 10 +- .../tab/MarathonScreen/MarathonScreen.tsx | 29 +- packages/portal/src/config/marathon.tsx | 71 ++ packages/portal/src/config/marathonContext.ts | 20 + packages/portal/src/config/storage.tsx | 3 + .../elements/singletons/NavigationMenu.tsx | 60 +- packages/portal/src/main.tsx | 5 +- .../overview/MarathonOverviewPage.tsx | 6 +- .../committee/CommitteeRepository.ts | 6 +- .../server/src/resolvers/MarathonResolver.ts | 2 +- schema.graphql | 1078 +++++++++++++---- 17 files changed, 1039 insertions(+), 323 deletions(-) create mode 100644 packages/portal/src/config/marathon.tsx create mode 100644 packages/portal/src/config/marathonContext.ts create mode 100644 packages/portal/src/config/storage.tsx diff --git a/eslint/base.ts b/eslint/base.ts index 655104dd..639e068c 100644 --- a/eslint/base.ts +++ b/eslint/base.ts @@ -28,8 +28,14 @@ const rules: Linter.RulesRecord = { "prefer-destructuring": [ "error", { - array: false, - object: true, + VariableDeclarator: { + array: false, + object: true, + }, + AssignmentExpression: { + array: false, + object: false, + }, }, { enforceForRenamedProperties: false, diff --git a/eslint/out/base.js b/eslint/out/base.js index dc8f84e8..f29be734 100644 --- a/eslint/out/base.js +++ b/eslint/out/base.js @@ -26,8 +26,14 @@ const rules = { "prefer-destructuring": [ "error", { - array: false, - object: true, + VariableDeclarator: { + array: false, + object: true, + }, + AssignmentExpression: { + array: false, + object: false, + }, }, { enforceForRenamedProperties: false, diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index dc069d95..443ddaf3 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -13,6 +13,8 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { + "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n": types.ActiveMarathonDocument, + "\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n": types.SelectedMarathonDocument, "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, "\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n": types.SingleNotificationFragmentFragmentDoc, @@ -69,7 +71,7 @@ const documents = { "\n fragment ImagesTableFragment on ImageNode {\n id\n url\n thumbHash\n height\n width\n alt\n mimeType\n createdAt\n }\n": types.ImagesTableFragmentFragmentDoc, "\n query ImagesTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [ImageResolverKeyedDateFilterItem!]\n $isNullFilters: [ImageResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [ImageResolverKeyedOneOfFilterItem!]\n $stringFilters: [ImageResolverKeyedStringFilterItem!]\n $numericFilters: [ImageResolverKeyedNumericFilterItem!]\n ) {\n images(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n numericFilters: $numericFilters\n ) {\n page\n pageSize\n total\n data {\n ...ImagesTableFragment\n }\n }\n }\n": types.ImagesTableDocument, "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n id\n }\n }\n ": types.CreateMarathonDocument, - "\n query MarathonOverviewPage {\n nextMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n": types.MarathonOverviewPageDocument, + "\n query MarathonOverviewPage {\n latestMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n": types.MarathonOverviewPageDocument, "\n fragment MarathonTableFragment on MarathonNode {\n id\n year\n startDate\n endDate\n }\n": types.MarathonTableFragmentFragmentDoc, "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n ": types.EditMarathonDocument, "\n query GetMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n ": types.GetMarathonDocument, @@ -101,6 +103,14 @@ const documents = { */ export function graphql(source: string): unknown; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -328,7 +338,7 @@ export function graphql(source: "\n mutation CreateMarathon($input: CreateM /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query MarathonOverviewPage {\n nextMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n"): (typeof documents)["\n query MarathonOverviewPage {\n nextMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query MarathonOverviewPage {\n latestMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n"): (typeof documents)["\n query MarathonOverviewPage {\n latestMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index a20206e6..8c14dee9 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -1654,6 +1654,7 @@ export type Query = { readonly fundraisingEntry: FundraisingEntryNode; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; + readonly latestMarathon?: Maybe; readonly listPeople: ListPeopleResponse; readonly loginState: LoginState; readonly marathon: MarathonNode; @@ -1661,7 +1662,6 @@ export type Query = { readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; - readonly nextMarathon?: Maybe; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -2152,6 +2152,18 @@ export type UpdateFundraisingAssignmentInput = { readonly amount: Scalars['Float']['input']; }; +export type ActiveMarathonQueryVariables = Exact<{ [key: string]: never; }>; + + +export type ActiveMarathonQuery = { readonly __typename?: 'Query', readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null }; + +export type SelectedMarathonQueryVariables = Exact<{ + marathonId: Scalars['String']['input']; +}>; + + +export type SelectedMarathonQuery = { readonly __typename?: 'Query', readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } }; + export type ImagePickerQueryVariables = Exact<{ stringFilters?: InputMaybe | ImageResolverKeyedStringFilterItem>; }>; @@ -2542,7 +2554,7 @@ export type CreateMarathonMutation = { readonly __typename?: 'Mutation', readonl export type MarathonOverviewPageQueryVariables = Exact<{ [key: string]: never; }>; -export type MarathonOverviewPageQuery = { readonly __typename?: 'Query', readonly nextMarathon?: ( +export type MarathonOverviewPageQuery = { readonly __typename?: 'Query', readonly latestMarathon?: ( { readonly __typename?: 'MarathonNode' } & { ' $fragmentRefs'?: { 'MarathonViewerFragmentFragment': MarathonViewerFragmentFragment } } ) | null, readonly marathons: { readonly __typename?: 'ListMarathonsResponse', readonly data: ReadonlyArray<( @@ -2694,6 +2706,8 @@ export const EventViewerFragmentFragmentDoc = {"kind":"Document","definitions":[ export const ImagesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const MarathonTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; +export const ActiveMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; +export const SelectedMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectedMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"title"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"body"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"audience"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationAudienceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"url"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stageNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"title"},"value":{"kind":"Variable","name":{"kind":"Name","value":"title"}}},{"kind":"Argument","name":{"kind":"Name","value":"body"},"value":{"kind":"Variable","name":{"kind":"Name","value":"body"}}},{"kind":"Argument","name":{"kind":"Name","value":"audience"},"value":{"kind":"Variable","name":{"kind":"Name","value":"audience"}}},{"kind":"Argument","name":{"kind":"Name","value":"url"},"value":{"kind":"Variable","name":{"kind":"Name","value":"url"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; @@ -2734,7 +2748,7 @@ export const DeleteFeedItemDocument = {"kind":"Document","definitions":[{"kind": export const CreateImageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateImage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateImageInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createImage"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const ImagesTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagesTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedNumericFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"numericFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImagesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const CreateMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const MarathonOverviewPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonOverviewPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; +export const MarathonOverviewPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonOverviewPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; export const EditMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const GetMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const MarathonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index 6ac87cc5..f46cb151 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -19,7 +19,7 @@ const documents = { "\n fragment NotificationFragment on NotificationNode {\n id\n title\n body\n url\n }\n": types.NotificationFragmentFragmentDoc, "\n fragment NotificationDeliveryFragment on NotificationDeliveryNode {\n id\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n": types.NotificationDeliveryFragmentFragmentDoc, "\n query useAllowedLoginTypes {\n activeConfiguration(key: \"ALLOWED_LOGIN_TYPES\") {\n data {\n ...SimpleConfig\n }\n }\n }\n": types.UseAllowedLoginTypesDocument, - "\n query MarathonTime {\n nextMarathon {\n startDate\n endDate\n }\n }\n": types.MarathonTimeDocument, + "\n query MarathonTime {\n latestMarathon {\n startDate\n endDate\n }\n }\n": types.MarathonTimeDocument, "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n data {\n linkblue\n }\n }\n }\n": types.UseTabBarConfigDocument, "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n ": types.TriviaCrackDocument, "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, @@ -33,7 +33,7 @@ const documents = { "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: asc\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, "\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n": types.ServerFeedDocument, "\n fragment HourScreenFragment on MarathonHourNode {\n id\n title\n details\n durationInfo\n mapImages {\n ...ImageViewFragment\n }\n }\n": types.HourScreenFragmentFragmentDoc, - "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n nextMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n": types.MarathonScreenDocument, + "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n latestMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n": types.MarathonScreenDocument, "\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n": types.ScoreBoardFragmentFragmentDoc, "\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n": types.HighlightedTeamFragmentFragmentDoc, "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, @@ -82,7 +82,7 @@ export function graphql(source: "\n query useAllowedLoginTypes {\n activeCon /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query MarathonTime {\n nextMarathon {\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query MarathonTime {\n nextMarathon {\n startDate\n endDate\n }\n }\n"]; +export function graphql(source: "\n query MarathonTime {\n latestMarathon {\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query MarathonTime {\n latestMarathon {\n startDate\n endDate\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -138,7 +138,7 @@ export function graphql(source: "\n fragment HourScreenFragment on MarathonHour /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n nextMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n"): (typeof documents)["\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n nextMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n latestMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n"): (typeof documents)["\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n latestMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index 2112510d..c2fd3a60 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -1654,6 +1654,7 @@ export type Query = { readonly fundraisingEntry: FundraisingEntryNode; readonly image: GetImageByUuidResponse; readonly images: ListImagesResponse; + readonly latestMarathon?: Maybe; readonly listPeople: ListPeopleResponse; readonly loginState: LoginState; readonly marathon: MarathonNode; @@ -1661,7 +1662,6 @@ export type Query = { readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; - readonly nextMarathon?: Maybe; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -2179,7 +2179,7 @@ export type UseAllowedLoginTypesQuery = { readonly __typename?: 'Query', readonl export type MarathonTimeQueryVariables = Exact<{ [key: string]: never; }>; -export type MarathonTimeQuery = { readonly __typename?: 'Query', readonly nextMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null }; +export type MarathonTimeQuery = { readonly __typename?: 'Query', readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null }; export type UseTabBarConfigQueryVariables = Exact<{ [key: string]: never; }>; @@ -2268,7 +2268,7 @@ export type MarathonScreenQueryVariables = Exact<{ [key: string]: never; }>; export type MarathonScreenQuery = { readonly __typename?: 'Query', readonly currentMarathonHour?: ( { readonly __typename?: 'MarathonHourNode' } & { ' $fragmentRefs'?: { 'HourScreenFragmentFragment': HourScreenFragmentFragment } } - ) | null, readonly nextMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null, readonly hours: ReadonlyArray<( + ) | null, readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly startDate?: Date | string | null, readonly endDate?: Date | string | null, readonly hours: ReadonlyArray<( { readonly __typename?: 'MarathonHourNode' } & { ' $fragmentRefs'?: { 'HourScreenFragmentFragment': HourScreenFragmentFragment } } )> } | null }; @@ -2311,7 +2311,7 @@ export const ScoreBoardFragmentFragmentDoc = {"kind":"Document","definitions":[{ export const HighlightedTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const MyTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const UseAllowedLoginTypesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useAllowedLoginTypes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"ALLOWED_LOGIN_TYPES","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const MarathonTimeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonTime"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; +export const MarathonTimeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonTime"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useTabBarConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TAB_BAR_CONFIG","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; @@ -2320,6 +2320,6 @@ export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"k export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"asc"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; -export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"nextMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; +export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"desc"},{"kind":"EnumValue","value":"asc"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ActiveMarathonDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathonDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/mobile/src/common/hooks/useMarathonTime.ts b/packages/mobile/src/common/hooks/useMarathonTime.ts index 12044f81..61218cc7 100644 --- a/packages/mobile/src/common/hooks/useMarathonTime.ts +++ b/packages/mobile/src/common/hooks/useMarathonTime.ts @@ -12,7 +12,7 @@ export interface MarathonTime { const marathonTimeQuery = graphql(/* GraphQL */ ` query MarathonTime { - nextMarathon { + latestMarathon { startDate endDate } @@ -38,8 +38,8 @@ export function useMarathonTime(): { const marathonInterval = useMemo(() => { try { - if (data?.nextMarathon) { - const startTime = dateTimeFromSomething(data.nextMarathon.startDate); + if (data?.latestMarathon) { + const startTime = dateTimeFromSomething(data.latestMarathon.startDate); if (!startTime?.isValid) { Logger.warn( `Unrecognized marathon start time: ${startTime?.toString()}`, @@ -48,7 +48,7 @@ export function useMarathonTime(): { } ); } - const endTime = dateTimeFromSomething(data.nextMarathon.endDate); + const endTime = dateTimeFromSomething(data.latestMarathon.endDate); if (!endTime?.isValid) { Logger.warn( `Unrecognized marathon end time: ${endTime?.toString()}`, @@ -73,7 +73,7 @@ export function useMarathonTime(): { startTime: DateTime.fromMillis(0), endTime: DateTime.fromMillis(0), }; - }, [data?.nextMarathon]); + }, [data?.latestMarathon]); return { timesLoading: fetching, diff --git a/packages/mobile/src/navigation/root/tab/MarathonScreen/MarathonScreen.tsx b/packages/mobile/src/navigation/root/tab/MarathonScreen/MarathonScreen.tsx index 7c73db0c..4ccb88f3 100644 --- a/packages/mobile/src/navigation/root/tab/MarathonScreen/MarathonScreen.tsx +++ b/packages/mobile/src/navigation/root/tab/MarathonScreen/MarathonScreen.tsx @@ -19,7 +19,7 @@ const marathonScreenDocument = graphql(/* GraphQL */ ` currentMarathonHour { ...HourScreenFragment } - nextMarathon { + latestMarathon { startDate endDate hours { @@ -38,7 +38,7 @@ export const MarathonScreen = () => { }); const [lastGoodData, setLastGoodData] = useState(data); useEffect(() => { - if (data?.currentMarathonHour || data?.nextMarathon) { + if (data?.currentMarathonHour || data?.latestMarathon) { setLastGoodData(data); } }, [data]); @@ -78,15 +78,16 @@ export const MarathonScreen = () => { No Internet Connection, cannot load marathon information ); - } else if (lastGoodData?.nextMarathon && hourOverride != null) { + } else if (lastGoodData?.latestMarathon && hourOverride != null) { if (hourOverride < 0) { return ( setShowSecretMenu(true)} /> @@ -94,8 +95,8 @@ export const MarathonScreen = () => { } else { return ( refresh({ requestPolicy: "network-only" })} showSecretMenu={() => setShowSecretMenu(true)} /> @@ -110,14 +111,14 @@ export const MarathonScreen = () => { showSecretMenu={() => setShowSecretMenu(true)} /> ); - } else if (lastGoodData?.nextMarathon) { + } else if (lastGoodData?.latestMarathon) { return ( setShowSecretMenu(true)} /> @@ -132,7 +133,7 @@ export const MarathonScreen = () => { Logger.info("MarathonScreen has invalid data", { source: "MarathonScreen", context: { - nextMarathon: lastGoodData?.nextMarathon, + latestMarathon: lastGoodData?.latestMarathon, currentHour: lastGoodData?.currentMarathonHour, }, }); @@ -154,7 +155,7 @@ export const MarathonScreen = () => { hourOverride, isInternetReachable, lastGoodData?.currentMarathonHour, - lastGoodData?.nextMarathon, + lastGoodData?.latestMarathon, refresh, vpHeight, vpWidth, @@ -186,8 +187,8 @@ export const MarathonScreen = () => { if ( (!Number.isNaN(parsedText) && parsedText === -1) || (parsedText >= 0 && - data?.nextMarathon && - parsedText <= data.nextMarathon.hours.length) + data?.latestMarathon && + parsedText <= data.latestMarathon.hours.length) ) { setHourOverride(parsedText); } else { diff --git a/packages/portal/src/config/marathon.tsx b/packages/portal/src/config/marathon.tsx new file mode 100644 index 00000000..4e18ad27 --- /dev/null +++ b/packages/portal/src/config/marathon.tsx @@ -0,0 +1,71 @@ +import { dateTimeFromSomething } from "@ukdanceblue/common"; +import { graphql } from "@ukdanceblue/common/graphql-client-admin"; +import { useState } from "react"; +import { useQuery } from "urql"; + +import { marathonContext } from "./marathonContext"; +import { LocalStorageKeys } from "./storage"; + +const latestMarathonDocument = graphql(/* GraphQL */ ` + query ActiveMarathon { + latestMarathon { + id + year + startDate + endDate + } + } +`); + +const selectedMarathonDocument = graphql(/* GraphQL */ ` + query SelectedMarathon($marathonId: String!) { + marathon(uuid: $marathonId) { + id + year + startDate + endDate + } + } +`); + +export const MarathonConfigProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const [marathonId, setMarathonId] = useState( + localStorage.getItem(LocalStorageKeys.SelectedMarathon) || null + ); + + const [latestMarathonResult] = useQuery({ query: latestMarathonDocument }); + const [selectedMarathonResult] = useQuery({ + query: selectedMarathonDocument, + variables: { marathonId: marathonId ?? "" }, + pause: marathonId == null, + }); + + let marathon = null; + if (marathonId != null && selectedMarathonResult.data != null) { + marathon = selectedMarathonResult.data.marathon; + } else if (latestMarathonResult.data != null) { + marathon = latestMarathonResult.data.latestMarathon; + } + + return ( + + {children} + + ); +}; diff --git a/packages/portal/src/config/marathonContext.ts b/packages/portal/src/config/marathonContext.ts new file mode 100644 index 00000000..3d5b1cb4 --- /dev/null +++ b/packages/portal/src/config/marathonContext.ts @@ -0,0 +1,20 @@ +import type { DateTime } from "luxon"; +import { createContext, useContext } from "react"; + +export const marathonContext = createContext<{ + setMarathon: (marathonId: string | null) => void; + marathon: { + id: string; + year: string; + startDate: DateTime | null; + endDate: DateTime | null; + } | null; +}>({ + setMarathon: () => {}, + marathon: null, +}); + +export const useMarathon = () => { + const { marathon } = useContext(marathonContext); + return marathon; +}; diff --git a/packages/portal/src/config/storage.tsx b/packages/portal/src/config/storage.tsx new file mode 100644 index 00000000..1ad84177 --- /dev/null +++ b/packages/portal/src/config/storage.tsx @@ -0,0 +1,3 @@ +export const LocalStorageKeys = { + SelectedMarathon: "ukdb-selected-marathon", +} as const; diff --git a/packages/portal/src/elements/singletons/NavigationMenu.tsx b/packages/portal/src/elements/singletons/NavigationMenu.tsx index b1cecf5d..cfeb5400 100644 --- a/packages/portal/src/elements/singletons/NavigationMenu.tsx +++ b/packages/portal/src/elements/singletons/NavigationMenu.tsx @@ -1,12 +1,17 @@ import { LoadingOutlined, MoonOutlined, SunOutlined } from "@ant-design/icons"; import { themeConfigContext } from "@config/antThemeConfig"; import { API_BASE_URL } from "@config/api"; +import { useAntFeedback } from "@hooks/useAntFeedback"; import { useLoginState } from "@hooks/useLoginState"; import type { AuthorizationRule } from "@ukdanceblue/common"; -import { AccessLevel, checkAuthorization } from "@ukdanceblue/common"; +import { + AccessLevel, + checkAuthorization, + defaultAuthorization, +} from "@ukdanceblue/common"; import { Button, Menu } from "antd"; import type { ItemType } from "antd/es/menu/hooks/useItems"; -import { useContext, useMemo } from "react"; +import { useContext, useEffect, useMemo, useState } from "react"; interface NavItemType { slug: string; @@ -18,6 +23,7 @@ interface NavItemType { export const NavigationMenu = () => { const { dark, setDark } = useContext(themeConfigContext); + const { showErrorMessage } = useAntFeedback(); const { loggedIn, authorization } = useLoginState(); const navItems = useMemo((): NavItemType[] => { @@ -102,24 +108,50 @@ export const NavigationMenu = () => { ]; }, []); - const menuItems = useMemo((): ItemType[] => { - return navItems - .filter( - ({ authorizationRules }) => - !authorizationRules || - (authorization && - authorizationRules.some((authorizationRule) => - checkAuthorization(authorizationRule, authorization) - )) - ) - .map((item) => ({ + const [menuItems, setMenuItems] = useState([]); + + useEffect(() => { + const fetchMenuItems = async () => { + const filteredItems: NavItemType[] = []; + for (const item of navItems) { + if (!item.authorizationRules) { + filteredItems.push(item); + } else { + let isAuthorized = false; + for (const authorizationRule of item.authorizationRules) { + if ( + // eslint-disable-next-line no-await-in-loop + await checkAuthorization( + authorizationRule, + authorization ?? defaultAuthorization + ) + ) { + isAuthorized = true; + break; + } + } + if (isAuthorized) { + filteredItems.push(item); + } + } + } + + const updatedMenuItems = filteredItems.map((item) => ({ key: item.slug, title: item.title, label: ( {item.element ?? item.title} ), })); - }, [authorization, navItems]); + + setMenuItems(updatedMenuItems); + }; + + fetchMenuItems().catch((error: unknown) => { + void showErrorMessage({ content: "Failed to fetch menu items" }); + console.error("Failed to fetch menu items", error); + }); + }, [authorization, navItems, showErrorMessage]); const activeKeys = useMemo((): string[] => { const { pathname } = window.location; diff --git a/packages/portal/src/main.tsx b/packages/portal/src/main.tsx index 81e03747..5df36d0f 100644 --- a/packages/portal/src/main.tsx +++ b/packages/portal/src/main.tsx @@ -1,3 +1,4 @@ +import { MarathonConfigProvider } from "@config/marathon.tsx"; import { RouterProvider } from "@tanstack/react-router"; import { App as AntApp } from "antd"; import { StrictMode } from "react"; @@ -23,7 +24,9 @@ createRoot(document.getElementById("root")!).render( - + + + diff --git a/packages/portal/src/pages/marathon/overview/MarathonOverviewPage.tsx b/packages/portal/src/pages/marathon/overview/MarathonOverviewPage.tsx index b0bc5c92..442bc19b 100644 --- a/packages/portal/src/pages/marathon/overview/MarathonOverviewPage.tsx +++ b/packages/portal/src/pages/marathon/overview/MarathonOverviewPage.tsx @@ -10,7 +10,7 @@ import { MarathonsTable } from "./MarathonsTable"; const marathonOverviewPageDocument = graphql(/* GraphQL */ ` query MarathonOverviewPage { - nextMarathon { + latestMarathon { ...MarathonViewerFragment } marathons(sendAll: true) { @@ -41,10 +41,10 @@ export function MarathonOverviewPage() { Create New Marathon - {result.data?.nextMarathon || result.data?.marathons.data.length ? ( + {result.data?.latestMarathon || result.data?.marathons.data.length ? (

    Current Marathon

    - +

    All Marathons

    diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index d458bd39..c0bf9f7c 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -87,14 +87,14 @@ export class CommitteeRepository { } if (!marathonParam) { - const nextMarathon = await this.marathonRepository.findActiveMarathon(); - if (!nextMarathon) { + const latestMarathon = await this.marathonRepository.findActiveMarathon(); + if (!latestMarathon) { throw new DetailedError( ErrorCode.NotFound, "No upcoming marathon found and no marathon provided" ); } - marathonParam = { id: nextMarathon.id }; + marathonParam = { id: latestMarathon.id }; } else { // Check if the marathon exists const val = diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 8fa34468..ec110307 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -150,7 +150,7 @@ export class MarathonResolver } @Query(() => MarathonNode, { nullable: true }) - async nextMarathon() { + async latestMarathon() { const marathon = await this.marathonRepository.findActiveMarathon(); if (marathon == null) { return null; diff --git a/schema.graphql b/schema.graphql index 9caceb00..e652c1fb 100644 --- a/schema.graphql +++ b/schema.graphql @@ -8,33 +8,47 @@ type AbortScheduledNotificationResponse implements AbstractGraphQLOkResponse & G ok: Boolean! } -"""API response""" +""" +API response +""" interface AbstractGraphQLArrayOkResponse implements GraphQLBaseResponse { ok: Boolean! } -"""API response""" +""" +API response +""" interface AbstractGraphQLCreatedResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { ok: Boolean! uuid: String! } -"""API response""" +""" +API response +""" interface AbstractGraphQLOkResponse implements GraphQLBaseResponse { ok: Boolean! } -"""API response""" +""" +API response +""" interface AbstractGraphQLPaginatedResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -52,7 +66,9 @@ input AssignEntryToPersonInput { amount: Float! } -"""The source of authentication""" +""" +The source of authentication +""" enum AuthSource { Anonymous Demo @@ -60,7 +76,9 @@ enum AuthSource { None } -"""The identifier for a committee""" +""" +The identifier for a committee +""" enum CommitteeIdentifier { communityDevelopmentCommittee corporateCommittee @@ -87,7 +105,9 @@ type CommitteeMembershipNode implements Node { updatedAt: DateTimeISO } -"""Roles within a committee""" +""" +Roles within a committee +""" enum CommitteeRole { Chair Coordinator @@ -225,7 +245,9 @@ type DbFundsTeamInfo implements Node { name: String! } -"""DanceBlue roles""" +""" +DanceBlue roles +""" enum DbRole { Committee None @@ -301,10 +323,14 @@ enum DeviceResolverDateFilterKeys { } input DeviceResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: DeviceResolverDateFilterKeys! """ @@ -315,7 +341,9 @@ input DeviceResolverKeyedDateFilterItem { } input DeviceResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: DeviceResolverAllKeys! """ @@ -325,7 +353,9 @@ input DeviceResolverKeyedIsNullFilterItem { } input DeviceResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: Void! """ @@ -336,10 +366,14 @@ input DeviceResolverKeyedOneOfFilterItem { } input DeviceResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: DeviceResolverStringFilterKeys! """ @@ -361,7 +395,10 @@ type EffectiveCommitteeRole { """ A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. """ -scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") +scalar EmailAddress + @specifiedBy( + url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address" + ) type EventNode implements Node { createdAt: DateTimeISO @@ -402,10 +439,14 @@ enum EventResolverDateFilterKeys { } input EventResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: EventResolverDateFilterKeys! """ @@ -416,7 +457,9 @@ input EventResolverKeyedDateFilterItem { } input EventResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: EventResolverAllKeys! """ @@ -426,7 +469,9 @@ input EventResolverKeyedIsNullFilterItem { } input EventResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: Void! """ @@ -437,10 +482,14 @@ input EventResolverKeyedOneOfFilterItem { } input EventResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: EventResolverStringFilterKeys! """ @@ -506,10 +555,14 @@ enum FundraisingEntryResolverDateFilterKeys { } input FundraisingEntryResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: FundraisingEntryResolverDateFilterKeys! """ @@ -520,7 +573,9 @@ input FundraisingEntryResolverKeyedDateFilterItem { } input FundraisingEntryResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: FundraisingEntryResolverAllKeys! """ @@ -530,10 +585,14 @@ input FundraisingEntryResolverKeyedIsNullFilterItem { } input FundraisingEntryResolverKeyedNumericFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: FundraisingEntryResolverNumericFilterKeys! """ @@ -544,7 +603,9 @@ input FundraisingEntryResolverKeyedNumericFilterItem { } input FundraisingEntryResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: FundraisingEntryResolverOneOfFilterKeys! """ @@ -555,10 +616,14 @@ input FundraisingEntryResolverKeyedOneOfFilterItem { } input FundraisingEntryResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: FundraisingEntryResolverStringFilterKeys! """ @@ -631,7 +696,9 @@ type GetPointEntryByUuidResponse implements AbstractGraphQLOkResponse & GraphQLB ok: Boolean! } -"""API response""" +""" +API response +""" interface GraphQLBaseResponse { ok: Boolean! } @@ -662,10 +729,14 @@ enum ImageResolverDateFilterKeys { } input ImageResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: ImageResolverDateFilterKeys! """ @@ -676,7 +747,9 @@ input ImageResolverKeyedDateFilterItem { } input ImageResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: ImageResolverAllKeys! """ @@ -686,10 +759,14 @@ input ImageResolverKeyedIsNullFilterItem { } input ImageResolverKeyedNumericFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: ImageResolverNumericFilterKeys! """ @@ -700,7 +777,9 @@ input ImageResolverKeyedNumericFilterItem { } input ImageResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: Void! """ @@ -711,10 +790,14 @@ input ImageResolverKeyedOneOfFilterItem { } input ImageResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: ImageResolverStringFilterKeys! """ @@ -747,13 +830,19 @@ type ListDevicesResponse implements AbstractGraphQLArrayOkResponse & AbstractGra data: [DeviceNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -761,13 +850,19 @@ type ListEventsResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [EventNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -775,13 +870,19 @@ type ListFundraisingEntriesResponse implements AbstractGraphQLArrayOkResponse & data: [FundraisingEntryNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -789,13 +890,19 @@ type ListImagesResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [ImageNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -803,13 +910,19 @@ type ListMarathonsResponse implements AbstractGraphQLArrayOkResponse & AbstractG data: [MarathonNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -817,13 +930,19 @@ type ListNotificationDeliveriesResponse implements AbstractGraphQLArrayOkRespons data: [NotificationDeliveryNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -831,13 +950,19 @@ type ListNotificationsResponse implements AbstractGraphQLArrayOkResponse & Abstr data: [NotificationNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -845,13 +970,19 @@ type ListPeopleResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [PersonNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -859,13 +990,19 @@ type ListPointEntriesResponse implements AbstractGraphQLArrayOkResponse & Abstra data: [PointEntryNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -873,13 +1010,19 @@ type ListPointOpportunitiesResponse implements AbstractGraphQLArrayOkResponse & data: [PointOpportunityNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -887,13 +1030,19 @@ type ListTeamsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraph data: [TeamNode!]! ok: Boolean! - """The current page number (1-indexed)""" + """ + The current page number (1-indexed) + """ page: PositiveInt! - """The number of items per page""" + """ + The number of items per page + """ pageSize: NonNegativeInt! - """The total number of items""" + """ + The total number of items + """ total: NonNegativeInt! } @@ -953,10 +1102,14 @@ enum MarathonResolverDateFilterKeys { } input MarathonResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: MarathonResolverDateFilterKeys! """ @@ -967,7 +1120,9 @@ input MarathonResolverKeyedDateFilterItem { } input MarathonResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: MarathonResolverAllKeys! """ @@ -985,7 +1140,9 @@ type MembershipNode implements Node { updatedAt: DateTimeISO } -"""The position of a member on a team""" +""" +The position of a member on a team +""" enum MembershipPositionType { Captain Member @@ -994,22 +1151,41 @@ enum MembershipPositionType { type Mutation { abortScheduledNotification(uuid: String!): AbortScheduledNotificationResponse! acknowledgeDeliveryIssue(uuid: String!): AcknowledgeDeliveryIssueResponse! - addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! + addExistingImageToEvent( + eventId: String! + imageId: String! + ): AddEventImageResponse! addMap(imageUuid: String!, uuid: String!): MarathonHourNode! - addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! - assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! + addPersonToTeam( + personUuid: String! + teamUuid: String! + ): GetMembershipResponse! + assignEntryToPerson( + entryId: String! + input: AssignEntryToPersonInput! + personId: String! + ): FundraisingAssignmentNode! assignTeamToDbFundsTeam(dbFundsTeamId: Float!, teamId: String!): Void! attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! - createConfiguration(input: CreateConfigurationInput!): CreateConfigurationResponse! - createConfigurations(input: [CreateConfigurationInput!]!): CreateConfigurationResponse! + createConfiguration( + input: CreateConfigurationInput! + ): CreateConfigurationResponse! + createConfigurations( + input: [CreateConfigurationInput!]! + ): CreateConfigurationResponse! createEvent(input: CreateEventInput!): CreateEventResponse! createFeedItem(input: CreateFeedInput!): FeedNode! createImage(input: CreateImageInput!): ImageNode! createMarathon(input: CreateMarathonInput!): MarathonNode! - createMarathonHour(input: CreateMarathonHourInput!, marathonUuid: String!): MarathonHourNode! + createMarathonHour( + input: CreateMarathonHourInput! + marathonUuid: String! + ): MarathonHourNode! createPerson(input: CreatePersonInput!): CreatePersonResponse! createPointEntry(input: CreatePointEntryInput!): CreatePointEntryResponse! - createPointOpportunity(input: CreatePointOpportunityInput!): CreatePointOpportunityResponse! + createPointOpportunity( + input: CreatePointOpportunityInput! + ): CreatePointOpportunityResponse! createTeam(input: CreateTeamInput!, marathon: String!): CreateTeamResponse! deleteConfiguration(uuid: String!): DeleteConfigurationResponse! deleteDevice(uuid: String!): DeleteDeviceResponse! @@ -1031,31 +1207,55 @@ type Mutation { deletePointOpportunity(uuid: String!): DeletePointOpportunityResponse! deleteTeam(uuid: String!): DeleteTeamResponse! registerDevice(input: RegisterDeviceInput!): RegisterDeviceResponse! - removeImageFromEvent(eventId: String!, imageId: String!): RemoveEventImageResponse! + removeImageFromEvent( + eventId: String! + imageId: String! + ): RemoveEventImageResponse! removeImageFromFeedItem(feedItemUuid: String!): FeedNode! removeMap(imageUuid: String!, uuid: String!): Void! - scheduleNotification(sendAt: DateTimeISO!, uuid: String!): ScheduleNotificationResponse! + scheduleNotification( + sendAt: DateTimeISO! + uuid: String! + ): ScheduleNotificationResponse! - """Send a notification immediately.""" + """ + Send a notification immediately. + """ sendNotification(uuid: String!): SendNotificationResponse! setEvent(input: SetEventInput!, uuid: String!): SetEventResponse! setFeedItem(feedItemUuid: String!, input: SetFeedInput!): FeedNode! setImageAltText(alt: String!, uuid: String!): ImageNode! setImageUrl(uuid: String!): ImageNode! setMarathon(input: SetMarathonInput!, uuid: String!): MarathonNode! - setMarathonHour(input: SetMarathonHourInput!, uuid: String!): MarathonHourNode! + setMarathonHour( + input: SetMarathonHourInput! + uuid: String! + ): MarathonHourNode! setPerson(input: SetPersonInput!, uuid: String!): GetPersonResponse! - setPointOpportunity(input: SetPointOpportunityInput!, uuid: String!): SinglePointOpportunityResponse! + setPointOpportunity( + input: SetPointOpportunityInput! + uuid: String! + ): SinglePointOpportunityResponse! setTeam(input: SetTeamInput!, uuid: String!): SingleTeamResponse! - stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! - updateFundraisingAssignment(id: String!, input: UpdateFundraisingAssignmentInput!): FundraisingAssignmentNode! + stageNotification( + audience: NotificationAudienceInput! + body: String! + title: String! + url: String + ): StageNotificationResponse! + updateFundraisingAssignment( + id: String! + input: UpdateFundraisingAssignmentInput! + ): FundraisingAssignmentNode! } interface Node { id: ID! } -"""Integers that will have a value of 0 or more.""" +""" +Integers that will have a value of 0 or more. +""" scalar NonNegativeInt input NotificationAudienceInput { @@ -1065,7 +1265,9 @@ input NotificationAudienceInput { users: [String!] } -"""The number of delivery issues for a notification, broken down by type.""" +""" +The number of delivery issues for a notification, broken down by type. +""" type NotificationDeliveryIssueCount { DeviceNotRegistered: Int! InvalidCredentials: Int! @@ -1082,15 +1284,21 @@ type NotificationDeliveryNode implements Node { chunkUuid: String createdAt: DateTimeISO - """Any error message returned by Expo when sending the notification.""" + """ + Any error message returned by Expo when sending the notification. + """ deliveryError: String id: ID! notification: NotificationNode! - """The time the server received a delivery receipt from the user.""" + """ + The time the server received a delivery receipt from the user. + """ receiptCheckedAt: DateTimeISO - """The time the server sent the notification to Expo for delivery.""" + """ + The time the server sent the notification to Expo for delivery. + """ sentAt: DateTimeISO updatedAt: DateTimeISO } @@ -1111,10 +1319,14 @@ enum NotificationDeliveryResolverDateFilterKeys { } input NotificationDeliveryResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: NotificationDeliveryResolverDateFilterKeys! """ @@ -1125,7 +1337,9 @@ input NotificationDeliveryResolverKeyedDateFilterItem { } input NotificationDeliveryResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: NotificationDeliveryResolverAllKeys! """ @@ -1148,7 +1362,9 @@ type NotificationNode implements Node { """ sendAt: DateTimeISO - """The time the server started sending the notification.""" + """ + The time the server started sending the notification. + """ startedSendingAt: DateTimeISO title: String! updatedAt: DateTimeISO @@ -1173,10 +1389,14 @@ enum NotificationResolverDateFilterKeys { } input NotificationResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: NotificationResolverDateFilterKeys! """ @@ -1187,7 +1407,9 @@ input NotificationResolverKeyedDateFilterItem { } input NotificationResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: NotificationResolverAllKeys! """ @@ -1197,7 +1419,9 @@ input NotificationResolverKeyedIsNullFilterItem { } input NotificationResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: NotificationResolverOneOfFilterKeys! """ @@ -1208,10 +1432,14 @@ input NotificationResolverKeyedOneOfFilterItem { } input NotificationResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: NotificationResolverStringFilterKeys! """ @@ -1241,28 +1469,47 @@ enum NumericComparator { type PersonNode implements Node { assignedDonationEntries( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1280,7 +1527,9 @@ type PersonNode implements Node { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): CommitteeMembershipNode committees: [CommitteeMembershipNode!]! @@ -1307,7 +1556,9 @@ enum PersonResolverAllKeys { } input PersonResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: PersonResolverAllKeys! """ @@ -1317,7 +1568,9 @@ input PersonResolverKeyedIsNullFilterItem { } input PersonResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: PersonResolverOneOfFilterKeys! """ @@ -1328,10 +1581,14 @@ input PersonResolverKeyedOneOfFilterItem { } input PersonResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: PersonResolverStringFilterKeys! """ @@ -1375,10 +1632,14 @@ enum PointEntryResolverDateFilterKeys { } input PointEntryResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: PointEntryResolverDateFilterKeys! """ @@ -1389,7 +1650,9 @@ input PointEntryResolverKeyedDateFilterItem { } input PointEntryResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: PointEntryResolverAllKeys! """ @@ -1423,10 +1686,14 @@ enum PointOpportunityResolverDateFilterKeys { } input PointOpportunityResolverKeyedDateFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: NumericComparator! - """The field to filter on""" + """ + The field to filter on + """ field: PointOpportunityResolverDateFilterKeys! """ @@ -1437,7 +1704,9 @@ input PointOpportunityResolverKeyedDateFilterItem { } input PointOpportunityResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: PointOpportunityResolverAllKeys! """ @@ -1447,7 +1716,9 @@ input PointOpportunityResolverKeyedIsNullFilterItem { } input PointOpportunityResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: PointOpportunityResolverOneOfFilterKeys! """ @@ -1458,10 +1729,14 @@ input PointOpportunityResolverKeyedOneOfFilterItem { } input PointOpportunityResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: PointOpportunityResolverStringFilterKeys! """ @@ -1479,7 +1754,9 @@ enum PointOpportunityResolverStringFilterKeys { name } -"""Integers that will have a value greater than 0.""" +""" +Integers that will have a value greater than 0. +""" scalar PositiveInt type Query { @@ -1490,28 +1767,47 @@ type Query { dbFundsTeams(search: String!): [DbFundsTeamInfo!]! device(uuid: String!): GetDeviceByUuidResponse! devices( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [DeviceResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [DeviceResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [DeviceResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1529,33 +1825,54 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [DeviceResolverKeyedStringFilterItem!] ): ListDevicesResponse! event(uuid: String!): GetEventByUuidResponse! events( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [EventResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [EventResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [EventResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1573,34 +1890,55 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [EventResolverKeyedStringFilterItem!] ): ListEventsResponse! feed(limit: Int = 10): [FeedNode!]! fundraisingAssignment(id: String!): FundraisingAssignmentNode! fundraisingEntries( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1618,34 +1956,55 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! fundraisingEntry(id: String!): FundraisingEntryNode! image(uuid: String!): GetImageByUuidResponse! images( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [ImageResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [ImageResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: [ImageResolverKeyedNumericFilterItem!] - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [ImageResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1663,32 +2022,53 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [ImageResolverKeyedStringFilterItem!] ): ListImagesResponse! listPeople( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: Void - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [PersonResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [PersonResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1706,7 +2086,9 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [PersonResolverKeyedStringFilterItem!] ): ListPeopleResponse! loginState: LoginState! @@ -1714,28 +2096,47 @@ type Query { marathonForYear(year: String!): MarathonNode! marathonHour(uuid: String!): MarathonHourNode! marathons( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [MarathonResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [MarathonResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: Void - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1753,36 +2154,57 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: Void ): ListMarathonsResponse! me: GetPersonResponse! - nextMarathon: MarathonNode + latestMarathon: MarathonNode notification(uuid: String!): GetNotificationByUuidResponse! notificationDeliveries( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [NotificationDeliveryResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [NotificationDeliveryResolverKeyedIsNullFilterItem!] notificationUuid: String! - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: Void - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1800,32 +2222,53 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: Void ): ListNotificationDeliveriesResponse! notifications( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [NotificationResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [NotificationResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [NotificationResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1843,34 +2286,55 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [NotificationResolverKeyedStringFilterItem!] ): ListNotificationsResponse! person(uuid: String!): GetPersonResponse! personByLinkBlue(linkBlueId: String!): GetPersonResponse! pointEntries( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [PointEntryResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [PointEntryResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: Void - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1888,33 +2352,54 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: Void ): ListPointEntriesResponse! pointEntry(uuid: String!): GetPointEntryByUuidResponse! pointOpportunities( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [PointOpportunityResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [PointOpportunityResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [PointOpportunityResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1932,37 +2417,58 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [PointOpportunityResolverKeyedStringFilterItem!] ): ListPointOpportunitiesResponse! pointOpportunity(uuid: String!): SinglePointOpportunityResponse! searchPeopleByName(name: String!): GetPeopleResponse! team(uuid: String!): SingleTeamResponse! teams( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: Void - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [TeamResolverKeyedIsNullFilterItem!] legacyStatus: [TeamLegacyStatus!] marathonYear: [String!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: Void - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [TeamResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -1980,7 +2486,9 @@ type Query { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [TeamResolverKeyedStringFilterItem!] type: [TeamType!] visibility: [DbRole!] @deprecated(reason: "Use type") @@ -1990,13 +2498,19 @@ type Query { input RegisterDeviceInput { deviceId: String! - """The Expo push token of the device""" + """ + The Expo push token of the device + """ expoPushToken: String - """The ID of the last user to log in on this device""" + """ + The ID of the last user to log in on this device + """ lastUserId: String - """base64 encoded SHA-256 hash of a secret known to the device""" + """ + base64 encoded SHA-256 hash of a secret known to the device + """ verifier: String! } @@ -2113,7 +2627,9 @@ enum StringComparator { SUBSTRING } -"""New Team vs Returning Team""" +""" +New Team vs Returning Team +""" enum TeamLegacyStatus { DemoTeam NewTeam @@ -2121,31 +2637,51 @@ enum TeamLegacyStatus { } type TeamNode implements Node { - captains: [MembershipNode!]! @deprecated(reason: "Just query the members field and filter by role") + captains: [MembershipNode!]! + @deprecated(reason: "Just query the members field and filter by role") createdAt: DateTimeISO fundraisingEntries( - """The boolean filters to apply to the query""" + """ + The boolean filters to apply to the query + """ booleanFilters: Void - """The date filters to apply to the query""" + """ + The date filters to apply to the query + """ dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """Whether to include deleted items in the results""" - includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") + """ + Whether to include deleted items in the results + """ + includeDeleted: Boolean + @deprecated( + reason: "Soft-deletion is no longer used in this project, this parameter is ignored" + ) - """The is-null filters to apply to the query""" + """ + The is-null filters to apply to the query + """ isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """The numeric filters to apply to the query""" + """ + The numeric filters to apply to the query + """ numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """The one-of filters to apply to the query""" + """ + The one-of filters to apply to the query + """ oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """The page number to return, defaults to 1""" + """ + The page number to return, defaults to 1 + """ page: Int - """The number of items to return per page, defaults to 10""" + """ + The number of items to return per page, defaults to 10 + """ pageSize: Int """ @@ -2163,7 +2699,9 @@ type TeamNode implements Node { """ sortDirection: [SortDirection!] - """The string filters to apply to the query""" + """ + The string filters to apply to the query + """ stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! id: ID! @@ -2185,7 +2723,9 @@ enum TeamResolverAllKeys { } input TeamResolverKeyedIsNullFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: TeamResolverAllKeys! """ @@ -2195,7 +2735,9 @@ input TeamResolverKeyedIsNullFilterItem { } input TeamResolverKeyedOneOfFilterItem { - """The field to filter on""" + """ + The field to filter on + """ field: TeamResolverOneOfFilterKeys! """ @@ -2206,10 +2748,14 @@ input TeamResolverKeyedOneOfFilterItem { } input TeamResolverKeyedStringFilterItem { - """The comparator to use for the filter""" + """ + The comparator to use for the filter + """ comparison: StringComparator! - """The field to filter on""" + """ + The field to filter on + """ field: TeamResolverStringFilterKeys! """ @@ -2229,7 +2775,9 @@ enum TeamResolverStringFilterKeys { name } -"""Types of teams""" +""" +Types of teams +""" enum TeamType { Committee Morale @@ -2245,5 +2793,7 @@ input UpdateFundraisingAssignmentInput { amount: Float! } -"""Represents NULL values""" -scalar Void \ No newline at end of file +""" +Represents NULL values +""" +scalar Void From 51433484508e1020921564bfaff370ba6ab24bd5 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 03:23:50 +0000 Subject: [PATCH 110/153] Implement Marathon selection --- .../common/lib/graphql-client-admin/gql.ts | 4 +- .../lib/graphql-client-admin/graphql.ts | 4 +- packages/portal/src/config/marathon.tsx | 22 +- packages/portal/src/config/marathonContext.ts | 9 + .../elements/singletons/NavigationMenu.tsx | 318 ++--- packages/portal/src/hooks/useLoginState.ts | 54 +- schema.graphql | 1078 ++++------------- 7 files changed, 495 insertions(+), 994 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 443ddaf3..80f998b9 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -13,7 +13,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n": types.ActiveMarathonDocument, + "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n marathons(sendAll: true) {\n data {\n id\n year\n }\n }\n }\n": types.ActiveMarathonDocument, "\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n": types.SelectedMarathonDocument, "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, @@ -106,7 +106,7 @@ export function graphql(source: string): unknown; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n }\n"]; +export function graphql(source: "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n marathons(sendAll: true) {\n data {\n id\n year\n }\n }\n }\n"): (typeof documents)["\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n marathons(sendAll: true) {\n data {\n id\n year\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 8c14dee9..dcefb0d5 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -2155,7 +2155,7 @@ export type UpdateFundraisingAssignmentInput = { export type ActiveMarathonQueryVariables = Exact<{ [key: string]: never; }>; -export type ActiveMarathonQuery = { readonly __typename?: 'Query', readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null }; +export type ActiveMarathonQuery = { readonly __typename?: 'Query', readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null, readonly marathons: { readonly __typename?: 'ListMarathonsResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string }> } }; export type SelectedMarathonQueryVariables = Exact<{ marathonId: Scalars['String']['input']; @@ -2706,7 +2706,7 @@ export const EventViewerFragmentFragmentDoc = {"kind":"Document","definitions":[ export const ImagesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const MarathonTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; -export const ActiveMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; +export const ActiveMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}}]}}]}}]} as unknown as DocumentNode; export const SelectedMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectedMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/portal/src/config/marathon.tsx b/packages/portal/src/config/marathon.tsx index 4e18ad27..2ce0cdf3 100644 --- a/packages/portal/src/config/marathon.tsx +++ b/packages/portal/src/config/marathon.tsx @@ -1,6 +1,6 @@ import { dateTimeFromSomething } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/graphql-client-admin"; -import { useState } from "react"; +import { useMemo, useState } from "react"; import { useQuery } from "urql"; import { marathonContext } from "./marathonContext"; @@ -14,6 +14,12 @@ const latestMarathonDocument = graphql(/* GraphQL */ ` startDate endDate } + marathons(sendAll: true) { + data { + id + year + } + } } `); @@ -51,6 +57,13 @@ export const MarathonConfigProvider = ({ marathon = latestMarathonResult.data.latestMarathon; } + const startDate = useMemo(() => { + return dateTimeFromSomething(marathon?.startDate) ?? null; + }, [marathon?.startDate]); + const endDate = useMemo(() => { + return dateTimeFromSomething(marathon?.endDate) ?? null; + }, [marathon?.endDate]); + return ( {children} diff --git a/packages/portal/src/config/marathonContext.ts b/packages/portal/src/config/marathonContext.ts index 3d5b1cb4..f44733ea 100644 --- a/packages/portal/src/config/marathonContext.ts +++ b/packages/portal/src/config/marathonContext.ts @@ -9,9 +9,18 @@ export const marathonContext = createContext<{ startDate: DateTime | null; endDate: DateTime | null; } | null; + marathons: + | readonly { + id: string; + year: string; + }[] + | null; + loading: boolean; }>({ setMarathon: () => {}, marathon: null, + marathons: [], + loading: true, }); export const useMarathon = () => { diff --git a/packages/portal/src/elements/singletons/NavigationMenu.tsx b/packages/portal/src/elements/singletons/NavigationMenu.tsx index cfeb5400..fd087743 100644 --- a/packages/portal/src/elements/singletons/NavigationMenu.tsx +++ b/packages/portal/src/elements/singletons/NavigationMenu.tsx @@ -1,6 +1,7 @@ -import { LoadingOutlined, MoonOutlined, SunOutlined } from "@ant-design/icons"; +import { MoonOutlined, SunOutlined } from "@ant-design/icons"; import { themeConfigContext } from "@config/antThemeConfig"; import { API_BASE_URL } from "@config/api"; +import { marathonContext } from "@config/marathonContext"; import { useAntFeedback } from "@hooks/useAntFeedback"; import { useLoginState } from "@hooks/useLoginState"; import type { AuthorizationRule } from "@ukdanceblue/common"; @@ -9,9 +10,8 @@ import { checkAuthorization, defaultAuthorization, } from "@ukdanceblue/common"; -import { Button, Menu } from "antd"; -import type { ItemType } from "antd/es/menu/hooks/useItems"; -import { useContext, useEffect, useMemo, useState } from "react"; +import { Button, Menu, Select } from "antd"; +import { useContext, useEffect, useState } from "react"; interface NavItemType { slug: string; @@ -21,94 +21,114 @@ interface NavItemType { authorizationRules?: AuthorizationRule[]; } -export const NavigationMenu = () => { - const { dark, setDark } = useContext(themeConfigContext); - const { showErrorMessage } = useAntFeedback(); - - const { loggedIn, authorization } = useLoginState(); - const navItems = useMemo((): NavItemType[] => { - return [ +const navItems = [ + { + slug: "home", + title: "Home", + url: "/", + }, + { + slug: "events", + title: "Events", + authorizationRules: [ { - slug: "home", - title: "Home", - url: "/", + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "teams", + title: "Teams", + authorizationRules: [ { - slug: "events", - title: "Events", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "people", + title: "People", + authorizationRules: [ { - slug: "teams", - title: "Teams", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "notifications", + title: "Notifications", + authorizationRules: [ { - slug: "people", - title: "People", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "marathon", + title: "Marathon", + authorizationRules: [ { - slug: "notifications", - title: "Notifications", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "feed", + title: "Feed", + authorizationRules: [ { - slug: "marathon", - title: "Marathon", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "images", + title: "Images", + authorizationRules: [ { - slug: "feed", - title: "Feed", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.CommitteeChairOrCoordinator, }, + ], + }, + { + slug: "config", + title: "Config", + authorizationRules: [ { - slug: "images", - title: "Images", - authorizationRules: [ - { - accessLevel: AccessLevel.CommitteeChairOrCoordinator, - }, - ], + accessLevel: AccessLevel.Admin, }, - { - slug: "config", - title: "Config", - authorizationRules: [ - { - accessLevel: AccessLevel.Admin, - }, - ], - }, - ]; - }, []); + ], + }, +]; +const { pathname, href } = window.location; +const activeKeys: string[] = []; +for (const item of navItems) { + if (item.url != null && (pathname || "/") === item.url) { + activeKeys.push(item.slug); + } else if (item.slug === pathname.slice(1)) { + activeKeys.push(item.slug); + } +} - const [menuItems, setMenuItems] = useState([]); +const loadingOption = [ + + Loading... + , +]; + +export const NavigationMenu = () => { + const { dark, setDark } = useContext(themeConfigContext); + const { showErrorMessage } = useAntFeedback(); + + const { loggedIn, authorization } = useLoginState(); + + const [menuItems, setMenuItems] = useState< + { + key: string; + title: string; + label: JSX.Element; + }[] + >([]); useEffect(() => { const fetchMenuItems = async () => { @@ -151,80 +171,84 @@ export const NavigationMenu = () => { void showErrorMessage({ content: "Failed to fetch menu items" }); console.error("Failed to fetch menu items", error); }); - }, [authorization, navItems, showErrorMessage]); + }, [authorization, showErrorMessage]); - const activeKeys = useMemo((): string[] => { - const { pathname } = window.location; - const activeKeys: string[] = []; - for (const item of navItems) { - if (item.url != null && pathname === item.url) { - activeKeys.push(item.slug); - } else if (item.slug === pathname.slice(1)) { - activeKeys.push(item.slug); - } - } - return activeKeys; - }, [navItems]); + const { setMarathon, marathon, loading, marathons } = + useContext(marathonContext); return ( - : undefined, - disabled: loggedIn == null, - label: loggedIn ? ( - - Logout - - ) : ( - - Login - - ), - style: { - background: "transparent", - marginLeft: "auto", - }, - }, - { - key: "dark", - title: "Dark", - label: ( - ); }; diff --git a/packages/portal/src/hooks/useLoginState.ts b/packages/portal/src/hooks/useLoginState.ts index 164e152c..e10cf8d3 100644 --- a/packages/portal/src/hooks/useLoginState.ts +++ b/packages/portal/src/hooks/useLoginState.ts @@ -1,6 +1,7 @@ import type { Authorization } from "@ukdanceblue/common"; import { defaultAuthorization, roleToAccessLevel } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/graphql-client-admin"; +import { useMemo } from "react"; import { useQuery } from "urql"; const loginStateDocument = graphql(/* GraphQL */ ` @@ -25,33 +26,34 @@ export function useLoginState(): { requestPolicy: "network-only", }); - if (fetching) { - return { - loggedIn: undefined, - authorization: undefined, - }; - } - - if (data == null) { - return { - loggedIn: false, - authorization: defaultAuthorization, - }; - } + return useMemo(() => { + if (fetching) { + return { + loggedIn: undefined, + authorization: undefined, + }; + } - const committees = data.loginState.effectiveCommitteeRoles.map( - ({ identifier, role }) => ({ identifier, role }) - ); + if (data == null) { + return { + loggedIn: false, + authorization: defaultAuthorization, + }; + } - return { - loggedIn: data.loginState.loggedIn, - authorization: { - committees, - dbRole: data.loginState.dbRole, - accessLevel: roleToAccessLevel({ - dbRole: data.loginState.dbRole, + const committees = data.loginState.effectiveCommitteeRoles.map( + ({ identifier, role }) => ({ identifier, role }) + ); + return { + loggedIn: data.loginState.loggedIn, + authorization: { committees, - }), - }, - }; + dbRole: data.loginState.dbRole, + accessLevel: roleToAccessLevel({ + dbRole: data.loginState.dbRole, + committees, + }), + }, + }; + }, [data, fetching]); } diff --git a/schema.graphql b/schema.graphql index e652c1fb..d35410c0 100644 --- a/schema.graphql +++ b/schema.graphql @@ -8,47 +8,33 @@ type AbortScheduledNotificationResponse implements AbstractGraphQLOkResponse & G ok: Boolean! } -""" -API response -""" +"""API response""" interface AbstractGraphQLArrayOkResponse implements GraphQLBaseResponse { ok: Boolean! } -""" -API response -""" +"""API response""" interface AbstractGraphQLCreatedResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { ok: Boolean! uuid: String! } -""" -API response -""" +"""API response""" interface AbstractGraphQLOkResponse implements GraphQLBaseResponse { ok: Boolean! } -""" -API response -""" +"""API response""" interface AbstractGraphQLPaginatedResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -66,9 +52,7 @@ input AssignEntryToPersonInput { amount: Float! } -""" -The source of authentication -""" +"""The source of authentication""" enum AuthSource { Anonymous Demo @@ -76,9 +60,7 @@ enum AuthSource { None } -""" -The identifier for a committee -""" +"""The identifier for a committee""" enum CommitteeIdentifier { communityDevelopmentCommittee corporateCommittee @@ -105,9 +87,7 @@ type CommitteeMembershipNode implements Node { updatedAt: DateTimeISO } -""" -Roles within a committee -""" +"""Roles within a committee""" enum CommitteeRole { Chair Coordinator @@ -245,9 +225,7 @@ type DbFundsTeamInfo implements Node { name: String! } -""" -DanceBlue roles -""" +"""DanceBlue roles""" enum DbRole { Committee None @@ -323,14 +301,10 @@ enum DeviceResolverDateFilterKeys { } input DeviceResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: DeviceResolverDateFilterKeys! """ @@ -341,9 +315,7 @@ input DeviceResolverKeyedDateFilterItem { } input DeviceResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: DeviceResolverAllKeys! """ @@ -353,9 +325,7 @@ input DeviceResolverKeyedIsNullFilterItem { } input DeviceResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: Void! """ @@ -366,14 +336,10 @@ input DeviceResolverKeyedOneOfFilterItem { } input DeviceResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: DeviceResolverStringFilterKeys! """ @@ -395,10 +361,7 @@ type EffectiveCommitteeRole { """ A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. """ -scalar EmailAddress - @specifiedBy( - url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address" - ) +scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") type EventNode implements Node { createdAt: DateTimeISO @@ -439,14 +402,10 @@ enum EventResolverDateFilterKeys { } input EventResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: EventResolverDateFilterKeys! """ @@ -457,9 +416,7 @@ input EventResolverKeyedDateFilterItem { } input EventResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: EventResolverAllKeys! """ @@ -469,9 +426,7 @@ input EventResolverKeyedIsNullFilterItem { } input EventResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: Void! """ @@ -482,14 +437,10 @@ input EventResolverKeyedOneOfFilterItem { } input EventResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: EventResolverStringFilterKeys! """ @@ -555,14 +506,10 @@ enum FundraisingEntryResolverDateFilterKeys { } input FundraisingEntryResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: FundraisingEntryResolverDateFilterKeys! """ @@ -573,9 +520,7 @@ input FundraisingEntryResolverKeyedDateFilterItem { } input FundraisingEntryResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: FundraisingEntryResolverAllKeys! """ @@ -585,14 +530,10 @@ input FundraisingEntryResolverKeyedIsNullFilterItem { } input FundraisingEntryResolverKeyedNumericFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: FundraisingEntryResolverNumericFilterKeys! """ @@ -603,9 +544,7 @@ input FundraisingEntryResolverKeyedNumericFilterItem { } input FundraisingEntryResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: FundraisingEntryResolverOneOfFilterKeys! """ @@ -616,14 +555,10 @@ input FundraisingEntryResolverKeyedOneOfFilterItem { } input FundraisingEntryResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: FundraisingEntryResolverStringFilterKeys! """ @@ -696,9 +631,7 @@ type GetPointEntryByUuidResponse implements AbstractGraphQLOkResponse & GraphQLB ok: Boolean! } -""" -API response -""" +"""API response""" interface GraphQLBaseResponse { ok: Boolean! } @@ -729,14 +662,10 @@ enum ImageResolverDateFilterKeys { } input ImageResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: ImageResolverDateFilterKeys! """ @@ -747,9 +676,7 @@ input ImageResolverKeyedDateFilterItem { } input ImageResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: ImageResolverAllKeys! """ @@ -759,14 +686,10 @@ input ImageResolverKeyedIsNullFilterItem { } input ImageResolverKeyedNumericFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: ImageResolverNumericFilterKeys! """ @@ -777,9 +700,7 @@ input ImageResolverKeyedNumericFilterItem { } input ImageResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: Void! """ @@ -790,14 +711,10 @@ input ImageResolverKeyedOneOfFilterItem { } input ImageResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: ImageResolverStringFilterKeys! """ @@ -830,19 +747,13 @@ type ListDevicesResponse implements AbstractGraphQLArrayOkResponse & AbstractGra data: [DeviceNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -850,19 +761,13 @@ type ListEventsResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [EventNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -870,19 +775,13 @@ type ListFundraisingEntriesResponse implements AbstractGraphQLArrayOkResponse & data: [FundraisingEntryNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -890,19 +789,13 @@ type ListImagesResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [ImageNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -910,19 +803,13 @@ type ListMarathonsResponse implements AbstractGraphQLArrayOkResponse & AbstractG data: [MarathonNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -930,19 +817,13 @@ type ListNotificationDeliveriesResponse implements AbstractGraphQLArrayOkRespons data: [NotificationDeliveryNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -950,19 +831,13 @@ type ListNotificationsResponse implements AbstractGraphQLArrayOkResponse & Abstr data: [NotificationNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -970,19 +845,13 @@ type ListPeopleResponse implements AbstractGraphQLArrayOkResponse & AbstractGrap data: [PersonNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -990,19 +859,13 @@ type ListPointEntriesResponse implements AbstractGraphQLArrayOkResponse & Abstra data: [PointEntryNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -1010,19 +873,13 @@ type ListPointOpportunitiesResponse implements AbstractGraphQLArrayOkResponse & data: [PointOpportunityNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -1030,19 +887,13 @@ type ListTeamsResponse implements AbstractGraphQLArrayOkResponse & AbstractGraph data: [TeamNode!]! ok: Boolean! - """ - The current page number (1-indexed) - """ + """The current page number (1-indexed)""" page: PositiveInt! - """ - The number of items per page - """ + """The number of items per page""" pageSize: NonNegativeInt! - """ - The total number of items - """ + """The total number of items""" total: NonNegativeInt! } @@ -1102,14 +953,10 @@ enum MarathonResolverDateFilterKeys { } input MarathonResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: MarathonResolverDateFilterKeys! """ @@ -1120,9 +967,7 @@ input MarathonResolverKeyedDateFilterItem { } input MarathonResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: MarathonResolverAllKeys! """ @@ -1140,9 +985,7 @@ type MembershipNode implements Node { updatedAt: DateTimeISO } -""" -The position of a member on a team -""" +"""The position of a member on a team""" enum MembershipPositionType { Captain Member @@ -1151,41 +994,22 @@ enum MembershipPositionType { type Mutation { abortScheduledNotification(uuid: String!): AbortScheduledNotificationResponse! acknowledgeDeliveryIssue(uuid: String!): AcknowledgeDeliveryIssueResponse! - addExistingImageToEvent( - eventId: String! - imageId: String! - ): AddEventImageResponse! + addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! addMap(imageUuid: String!, uuid: String!): MarathonHourNode! - addPersonToTeam( - personUuid: String! - teamUuid: String! - ): GetMembershipResponse! - assignEntryToPerson( - entryId: String! - input: AssignEntryToPersonInput! - personId: String! - ): FundraisingAssignmentNode! + addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! + assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! assignTeamToDbFundsTeam(dbFundsTeamId: Float!, teamId: String!): Void! attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! - createConfiguration( - input: CreateConfigurationInput! - ): CreateConfigurationResponse! - createConfigurations( - input: [CreateConfigurationInput!]! - ): CreateConfigurationResponse! + createConfiguration(input: CreateConfigurationInput!): CreateConfigurationResponse! + createConfigurations(input: [CreateConfigurationInput!]!): CreateConfigurationResponse! createEvent(input: CreateEventInput!): CreateEventResponse! createFeedItem(input: CreateFeedInput!): FeedNode! createImage(input: CreateImageInput!): ImageNode! createMarathon(input: CreateMarathonInput!): MarathonNode! - createMarathonHour( - input: CreateMarathonHourInput! - marathonUuid: String! - ): MarathonHourNode! + createMarathonHour(input: CreateMarathonHourInput!, marathonUuid: String!): MarathonHourNode! createPerson(input: CreatePersonInput!): CreatePersonResponse! createPointEntry(input: CreatePointEntryInput!): CreatePointEntryResponse! - createPointOpportunity( - input: CreatePointOpportunityInput! - ): CreatePointOpportunityResponse! + createPointOpportunity(input: CreatePointOpportunityInput!): CreatePointOpportunityResponse! createTeam(input: CreateTeamInput!, marathon: String!): CreateTeamResponse! deleteConfiguration(uuid: String!): DeleteConfigurationResponse! deleteDevice(uuid: String!): DeleteDeviceResponse! @@ -1207,55 +1031,31 @@ type Mutation { deletePointOpportunity(uuid: String!): DeletePointOpportunityResponse! deleteTeam(uuid: String!): DeleteTeamResponse! registerDevice(input: RegisterDeviceInput!): RegisterDeviceResponse! - removeImageFromEvent( - eventId: String! - imageId: String! - ): RemoveEventImageResponse! + removeImageFromEvent(eventId: String!, imageId: String!): RemoveEventImageResponse! removeImageFromFeedItem(feedItemUuid: String!): FeedNode! removeMap(imageUuid: String!, uuid: String!): Void! - scheduleNotification( - sendAt: DateTimeISO! - uuid: String! - ): ScheduleNotificationResponse! + scheduleNotification(sendAt: DateTimeISO!, uuid: String!): ScheduleNotificationResponse! - """ - Send a notification immediately. - """ + """Send a notification immediately.""" sendNotification(uuid: String!): SendNotificationResponse! setEvent(input: SetEventInput!, uuid: String!): SetEventResponse! setFeedItem(feedItemUuid: String!, input: SetFeedInput!): FeedNode! setImageAltText(alt: String!, uuid: String!): ImageNode! setImageUrl(uuid: String!): ImageNode! setMarathon(input: SetMarathonInput!, uuid: String!): MarathonNode! - setMarathonHour( - input: SetMarathonHourInput! - uuid: String! - ): MarathonHourNode! + setMarathonHour(input: SetMarathonHourInput!, uuid: String!): MarathonHourNode! setPerson(input: SetPersonInput!, uuid: String!): GetPersonResponse! - setPointOpportunity( - input: SetPointOpportunityInput! - uuid: String! - ): SinglePointOpportunityResponse! + setPointOpportunity(input: SetPointOpportunityInput!, uuid: String!): SinglePointOpportunityResponse! setTeam(input: SetTeamInput!, uuid: String!): SingleTeamResponse! - stageNotification( - audience: NotificationAudienceInput! - body: String! - title: String! - url: String - ): StageNotificationResponse! - updateFundraisingAssignment( - id: String! - input: UpdateFundraisingAssignmentInput! - ): FundraisingAssignmentNode! + stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! + updateFundraisingAssignment(id: String!, input: UpdateFundraisingAssignmentInput!): FundraisingAssignmentNode! } interface Node { id: ID! } -""" -Integers that will have a value of 0 or more. -""" +"""Integers that will have a value of 0 or more.""" scalar NonNegativeInt input NotificationAudienceInput { @@ -1265,9 +1065,7 @@ input NotificationAudienceInput { users: [String!] } -""" -The number of delivery issues for a notification, broken down by type. -""" +"""The number of delivery issues for a notification, broken down by type.""" type NotificationDeliveryIssueCount { DeviceNotRegistered: Int! InvalidCredentials: Int! @@ -1284,21 +1082,15 @@ type NotificationDeliveryNode implements Node { chunkUuid: String createdAt: DateTimeISO - """ - Any error message returned by Expo when sending the notification. - """ + """Any error message returned by Expo when sending the notification.""" deliveryError: String id: ID! notification: NotificationNode! - """ - The time the server received a delivery receipt from the user. - """ + """The time the server received a delivery receipt from the user.""" receiptCheckedAt: DateTimeISO - """ - The time the server sent the notification to Expo for delivery. - """ + """The time the server sent the notification to Expo for delivery.""" sentAt: DateTimeISO updatedAt: DateTimeISO } @@ -1319,14 +1111,10 @@ enum NotificationDeliveryResolverDateFilterKeys { } input NotificationDeliveryResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: NotificationDeliveryResolverDateFilterKeys! """ @@ -1337,9 +1125,7 @@ input NotificationDeliveryResolverKeyedDateFilterItem { } input NotificationDeliveryResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: NotificationDeliveryResolverAllKeys! """ @@ -1362,9 +1148,7 @@ type NotificationNode implements Node { """ sendAt: DateTimeISO - """ - The time the server started sending the notification. - """ + """The time the server started sending the notification.""" startedSendingAt: DateTimeISO title: String! updatedAt: DateTimeISO @@ -1389,14 +1173,10 @@ enum NotificationResolverDateFilterKeys { } input NotificationResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: NotificationResolverDateFilterKeys! """ @@ -1407,9 +1187,7 @@ input NotificationResolverKeyedDateFilterItem { } input NotificationResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: NotificationResolverAllKeys! """ @@ -1419,9 +1197,7 @@ input NotificationResolverKeyedIsNullFilterItem { } input NotificationResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: NotificationResolverOneOfFilterKeys! """ @@ -1432,14 +1208,10 @@ input NotificationResolverKeyedOneOfFilterItem { } input NotificationResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: NotificationResolverStringFilterKeys! """ @@ -1469,47 +1241,28 @@ enum NumericComparator { type PersonNode implements Node { assignedDonationEntries( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -1527,9 +1280,7 @@ type PersonNode implements Node { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): CommitteeMembershipNode committees: [CommitteeMembershipNode!]! @@ -1556,9 +1307,7 @@ enum PersonResolverAllKeys { } input PersonResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: PersonResolverAllKeys! """ @@ -1568,9 +1317,7 @@ input PersonResolverKeyedIsNullFilterItem { } input PersonResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: PersonResolverOneOfFilterKeys! """ @@ -1581,14 +1328,10 @@ input PersonResolverKeyedOneOfFilterItem { } input PersonResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: PersonResolverStringFilterKeys! """ @@ -1632,14 +1375,10 @@ enum PointEntryResolverDateFilterKeys { } input PointEntryResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: PointEntryResolverDateFilterKeys! """ @@ -1650,9 +1389,7 @@ input PointEntryResolverKeyedDateFilterItem { } input PointEntryResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: PointEntryResolverAllKeys! """ @@ -1686,14 +1423,10 @@ enum PointOpportunityResolverDateFilterKeys { } input PointOpportunityResolverKeyedDateFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: NumericComparator! - """ - The field to filter on - """ + """The field to filter on""" field: PointOpportunityResolverDateFilterKeys! """ @@ -1704,9 +1437,7 @@ input PointOpportunityResolverKeyedDateFilterItem { } input PointOpportunityResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: PointOpportunityResolverAllKeys! """ @@ -1716,9 +1447,7 @@ input PointOpportunityResolverKeyedIsNullFilterItem { } input PointOpportunityResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: PointOpportunityResolverOneOfFilterKeys! """ @@ -1729,14 +1458,10 @@ input PointOpportunityResolverKeyedOneOfFilterItem { } input PointOpportunityResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: PointOpportunityResolverStringFilterKeys! """ @@ -1754,9 +1479,7 @@ enum PointOpportunityResolverStringFilterKeys { name } -""" -Integers that will have a value greater than 0. -""" +"""Integers that will have a value greater than 0.""" scalar PositiveInt type Query { @@ -1767,47 +1490,28 @@ type Query { dbFundsTeams(search: String!): [DbFundsTeamInfo!]! device(uuid: String!): GetDeviceByUuidResponse! devices( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [DeviceResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [DeviceResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [DeviceResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -1825,54 +1529,33 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [DeviceResolverKeyedStringFilterItem!] ): ListDevicesResponse! event(uuid: String!): GetEventByUuidResponse! events( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [EventResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [EventResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [EventResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -1890,55 +1573,34 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [EventResolverKeyedStringFilterItem!] ): ListEventsResponse! feed(limit: Int = 10): [FeedNode!]! fundraisingAssignment(id: String!): FundraisingAssignmentNode! fundraisingEntries( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -1956,55 +1618,34 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! fundraisingEntry(id: String!): FundraisingEntryNode! image(uuid: String!): GetImageByUuidResponse! images( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [ImageResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [ImageResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: [ImageResolverKeyedNumericFilterItem!] - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [ImageResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2022,53 +1663,33 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [ImageResolverKeyedStringFilterItem!] ): ListImagesResponse! + latestMarathon: MarathonNode listPeople( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: Void - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [PersonResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [PersonResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2086,9 +1707,7 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [PersonResolverKeyedStringFilterItem!] ): ListPeopleResponse! loginState: LoginState! @@ -2096,47 +1715,28 @@ type Query { marathonForYear(year: String!): MarathonNode! marathonHour(uuid: String!): MarathonHourNode! marathons( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [MarathonResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [MarathonResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: Void - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2154,57 +1754,35 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: Void ): ListMarathonsResponse! me: GetPersonResponse! - latestMarathon: MarathonNode notification(uuid: String!): GetNotificationByUuidResponse! notificationDeliveries( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [NotificationDeliveryResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [NotificationDeliveryResolverKeyedIsNullFilterItem!] notificationUuid: String! - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: Void - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2222,53 +1800,32 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: Void ): ListNotificationDeliveriesResponse! notifications( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [NotificationResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [NotificationResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [NotificationResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2286,55 +1843,34 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [NotificationResolverKeyedStringFilterItem!] ): ListNotificationsResponse! person(uuid: String!): GetPersonResponse! personByLinkBlue(linkBlueId: String!): GetPersonResponse! pointEntries( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [PointEntryResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [PointEntryResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: Void - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2352,54 +1888,33 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: Void ): ListPointEntriesResponse! pointEntry(uuid: String!): GetPointEntryByUuidResponse! pointOpportunities( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [PointOpportunityResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [PointOpportunityResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [PointOpportunityResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2417,58 +1932,37 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [PointOpportunityResolverKeyedStringFilterItem!] ): ListPointOpportunitiesResponse! pointOpportunity(uuid: String!): SinglePointOpportunityResponse! searchPeopleByName(name: String!): GetPeopleResponse! team(uuid: String!): SingleTeamResponse! teams( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: Void - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [TeamResolverKeyedIsNullFilterItem!] legacyStatus: [TeamLegacyStatus!] marathonYear: [String!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: Void - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [TeamResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2486,9 +1980,7 @@ type Query { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [TeamResolverKeyedStringFilterItem!] type: [TeamType!] visibility: [DbRole!] @deprecated(reason: "Use type") @@ -2498,19 +1990,13 @@ type Query { input RegisterDeviceInput { deviceId: String! - """ - The Expo push token of the device - """ + """The Expo push token of the device""" expoPushToken: String - """ - The ID of the last user to log in on this device - """ + """The ID of the last user to log in on this device""" lastUserId: String - """ - base64 encoded SHA-256 hash of a secret known to the device - """ + """base64 encoded SHA-256 hash of a secret known to the device""" verifier: String! } @@ -2627,9 +2113,7 @@ enum StringComparator { SUBSTRING } -""" -New Team vs Returning Team -""" +"""New Team vs Returning Team""" enum TeamLegacyStatus { DemoTeam NewTeam @@ -2637,51 +2121,31 @@ enum TeamLegacyStatus { } type TeamNode implements Node { - captains: [MembershipNode!]! - @deprecated(reason: "Just query the members field and filter by role") + captains: [MembershipNode!]! @deprecated(reason: "Just query the members field and filter by role") createdAt: DateTimeISO fundraisingEntries( - """ - The boolean filters to apply to the query - """ + """The boolean filters to apply to the query""" booleanFilters: Void - """ - The date filters to apply to the query - """ + """The date filters to apply to the query""" dateFilters: [FundraisingEntryResolverKeyedDateFilterItem!] - """ - Whether to include deleted items in the results - """ - includeDeleted: Boolean - @deprecated( - reason: "Soft-deletion is no longer used in this project, this parameter is ignored" - ) + """Whether to include deleted items in the results""" + includeDeleted: Boolean @deprecated(reason: "Soft-deletion is no longer used in this project, this parameter is ignored") - """ - The is-null filters to apply to the query - """ + """The is-null filters to apply to the query""" isNullFilters: [FundraisingEntryResolverKeyedIsNullFilterItem!] - """ - The numeric filters to apply to the query - """ + """The numeric filters to apply to the query""" numericFilters: [FundraisingEntryResolverKeyedNumericFilterItem!] - """ - The one-of filters to apply to the query - """ + """The one-of filters to apply to the query""" oneOfFilters: [FundraisingEntryResolverKeyedOneOfFilterItem!] - """ - The page number to return, defaults to 1 - """ + """The page number to return, defaults to 1""" page: Int - """ - The number of items to return per page, defaults to 10 - """ + """The number of items to return per page, defaults to 10""" pageSize: Int """ @@ -2699,9 +2163,7 @@ type TeamNode implements Node { """ sortDirection: [SortDirection!] - """ - The string filters to apply to the query - """ + """The string filters to apply to the query""" stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! id: ID! @@ -2723,9 +2185,7 @@ enum TeamResolverAllKeys { } input TeamResolverKeyedIsNullFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: TeamResolverAllKeys! """ @@ -2735,9 +2195,7 @@ input TeamResolverKeyedIsNullFilterItem { } input TeamResolverKeyedOneOfFilterItem { - """ - The field to filter on - """ + """The field to filter on""" field: TeamResolverOneOfFilterKeys! """ @@ -2748,14 +2206,10 @@ input TeamResolverKeyedOneOfFilterItem { } input TeamResolverKeyedStringFilterItem { - """ - The comparator to use for the filter - """ + """The comparator to use for the filter""" comparison: StringComparator! - """ - The field to filter on - """ + """The field to filter on""" field: TeamResolverStringFilterKeys! """ @@ -2775,9 +2229,7 @@ enum TeamResolverStringFilterKeys { name } -""" -Types of teams -""" +"""Types of teams""" enum TeamType { Committee Morale @@ -2793,7 +2245,5 @@ input UpdateFundraisingAssignmentInput { amount: Float! } -""" -Represents NULL values -""" -scalar Void +"""Represents NULL values""" +scalar Void \ No newline at end of file From 2e3c5cb44e4ad0d14f67c658db39fc75ce9af101 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 03:28:27 +0000 Subject: [PATCH 111/153] Remove unused imports and commented code in PersonCreator and PersonEditor files --- .../src/elements/forms/person/create/PersonCreator.tsx | 5 ++--- .../src/elements/forms/person/edit/PersonEditor.tsx | 7 +++---- .../elements/forms/team/create/useTeamCreatorForm.ts | 10 ++++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx index 35cce087..b3dd4310 100644 --- a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx +++ b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx @@ -1,5 +1,4 @@ import { useNavigate } from "@tanstack/react-router"; -import { CommitteeRole, committeeNames } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData } from "@ukdanceblue/common/graphql-client-admin"; import { App, Button, Empty, Flex, Form, Input, Select } from "antd"; @@ -171,7 +170,7 @@ export function PersonCreator({ )} /> - ( )} - /> + /> */}

    Note: If someone is captain of a team that also means they are a member of that team, so you don't need to select both. diff --git a/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx b/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx index 136b360e..4c141b76 100644 --- a/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx +++ b/packages/portal/src/elements/forms/person/edit/PersonEditor.tsx @@ -1,4 +1,3 @@ -import { CommitteeRole, committeeNames } from "@ukdanceblue/common"; import type { FragmentType } from "@ukdanceblue/common/graphql-client-admin"; import { getFragmentData } from "@ukdanceblue/common/graphql-client-admin"; import { App, Button, Empty, Flex, Form, Input, Select } from "antd"; @@ -184,8 +183,8 @@ export function PersonEditor({ )} /> - ( )} - /> + /> */}

    Note: If someone is captain of a team that also means they are a member of that team, so you don't need to select both. diff --git a/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts b/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts index 488c8b3c..c3898ff6 100644 --- a/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts +++ b/packages/portal/src/elements/forms/team/create/useTeamCreatorForm.ts @@ -1,3 +1,5 @@ +import { useMarathon } from "@config/marathonContext"; +import { useAntFeedback } from "@hooks/useAntFeedback"; import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; import { useForm } from "@tanstack/react-form"; import { TeamLegacyStatus, TeamType } from "@ukdanceblue/common"; @@ -22,6 +24,9 @@ export function useTeamCreatorForm( loadingMessage: "Saving team...", }); + const marathonId = useMarathon()?.id; + const { showErrorMessage } = useAntFeedback(); + const Form = useForm({ defaultValues: { name: "", @@ -29,12 +34,17 @@ export function useTeamCreatorForm( type: TeamType.Spirit, }, onSubmit: async (values) => { + if (!marathonId) { + void showErrorMessage("No marathon selected"); + return; + } const { data } = await createTeam({ input: { name: values.name, legacyStatus: values.legacyStatus, type: values.type, }, + marathonUuid: marathonId, }); return afterSubmit?.(data?.createTeam); From 5b28daff7fa9be6bce9f7320fff941e8aa995c87 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 03:47:05 +0000 Subject: [PATCH 112/153] Update team repository to use marathonId instead of marathonYear --- .../common/lib/graphql-client-admin/gql.ts | 4 +- .../lib/graphql-client-admin/graphql.ts | 13 +++-- .../lib/graphql-client-public/graphql.ts | 7 ++- .../forms/team/edit/useTeamEditorForm.ts | 2 - .../portal/src/elements/tables/TeamsTable.tsx | 51 +++++++------------ .../src/repositories/team/TeamRepository.ts | 4 +- .../repositories/team/teamRepositoryUtils.ts | 4 +- packages/server/src/resolvers/TeamResolver.ts | 22 +++----- schema.graphql | 7 ++- 9 files changed, 43 insertions(+), 71 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 80f998b9..64f373be 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -40,7 +40,7 @@ const documents = { "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n primaryCommittee {\n identifier\n role\n }\n }\n": types.PeopleTableFragmentFragmentDoc, "\n query PeopleTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [PersonResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [PersonResolverKeyedOneOfFilterItem!]\n $stringFilters: [PersonResolverKeyedStringFilterItem!]\n ) {\n listPeople(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...PeopleTableFragment\n }\n }\n }\n": types.PeopleTableDocument, "\n query TeamsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [TeamResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [TeamResolverKeyedOneOfFilterItem!]\n $stringFilters: [TeamResolverKeyedStringFilterItem!]\n ) {\n teams(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...TeamsTableFragment\n }\n }\n }\n": types.TeamsTableDocument, - "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n": types.TeamsTableFragmentFragmentDoc, + "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n totalPoints\n }\n": types.TeamsTableFragmentFragmentDoc, "\n fragment NotificationDeliveriesTableFragment on NotificationDeliveryNode {\n id\n deliveryError\n receiptCheckedAt\n sentAt\n }\n": types.NotificationDeliveriesTableFragmentFragmentDoc, "\n query NotificationDeliveriesTableQuery(\n $notificationId: String!\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationDeliveryResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationDeliveryResolverKeyedIsNullFilterItem!]\n ) {\n notificationDeliveries(\n notificationUuid: $notificationId\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationDeliveriesTableFragment\n }\n }\n }\n": types.NotificationDeliveriesTableQueryDocument, "\n fragment NotificationsTableFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n": types.NotificationsTableFragmentFragmentDoc, @@ -214,7 +214,7 @@ export function graphql(source: "\n query TeamsTable(\n $page: Int\n $pag /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n"): (typeof documents)["\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n marathon {\n id\n year\n }\n totalPoints\n }\n"]; +export function graphql(source: "\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n totalPoints\n }\n"): (typeof documents)["\n fragment TeamsTableFragment on TeamNode {\n id\n type\n name\n legacyStatus\n totalPoints\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index dcefb0d5..bceec8d0 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -1934,7 +1934,7 @@ export type QueryTeamsArgs = { includeDeleted?: InputMaybe; isNullFilters?: InputMaybe>; legacyStatus?: InputMaybe>; - marathonYear?: InputMaybe>; + marathonId?: InputMaybe>; numericFilters?: InputMaybe; oneOfFilters?: InputMaybe>; page?: InputMaybe; @@ -2037,7 +2037,6 @@ export type SetPointOpportunityInput = { export type SetTeamInput = { readonly legacyStatus?: InputMaybe; - readonly marathonYear?: InputMaybe; readonly name?: InputMaybe; readonly persistentIdentifier?: InputMaybe; readonly type?: InputMaybe; @@ -2103,7 +2102,7 @@ export type TeamNodeFundraisingEntriesArgs = { export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', - MarathonYear: 'marathonYear', + MarathonId: 'marathonId', Name: 'name', Type: 'type' } as const; @@ -2136,7 +2135,7 @@ export type TeamResolverKeyedStringFilterItem = { export const TeamResolverOneOfFilterKeys = { LegacyStatus: 'legacyStatus', - MarathonYear: 'marathonYear', + MarathonId: 'marathonId', Type: 'type' } as const; @@ -2342,7 +2341,7 @@ export type TeamsTableQuery = { readonly __typename?: 'Query', readonly teams: { & { ' $fragmentRefs'?: { 'TeamsTableFragmentFragment': TeamsTableFragmentFragment } } )> } }; -export type TeamsTableFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly type: TeamType, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly totalPoints: number, readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string } } & { ' $fragmentName'?: 'TeamsTableFragmentFragment' }; +export type TeamsTableFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly type: TeamType, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly totalPoints: number } & { ' $fragmentName'?: 'TeamsTableFragmentFragment' }; export type NotificationDeliveriesTableFragmentFragment = { readonly __typename?: 'NotificationDeliveryNode', readonly id: string, readonly deliveryError?: string | null, readonly receiptCheckedAt?: Date | string | null, readonly sentAt?: Date | string | null } & { ' $fragmentName'?: 'NotificationDeliveriesTableFragmentFragment' }; @@ -2693,7 +2692,7 @@ export const TeamNameFragmentFragmentDoc = {"kind":"Document","definitions":[{"k export const PersonEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const TeamEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const PeopleTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const TeamsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; +export const TeamsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveriesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; export const PointEntryTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; @@ -2727,7 +2726,7 @@ export const CreatePointOpportunityDocument = {"kind":"Document","definitions":[ export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathon"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; +export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index c2fd3a60..cd435811 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -1934,7 +1934,7 @@ export type QueryTeamsArgs = { includeDeleted?: InputMaybe; isNullFilters?: InputMaybe>; legacyStatus?: InputMaybe>; - marathonYear?: InputMaybe>; + marathonId?: InputMaybe>; numericFilters?: InputMaybe; oneOfFilters?: InputMaybe>; page?: InputMaybe; @@ -2037,7 +2037,6 @@ export type SetPointOpportunityInput = { export type SetTeamInput = { readonly legacyStatus?: InputMaybe; - readonly marathonYear?: InputMaybe; readonly name?: InputMaybe; readonly persistentIdentifier?: InputMaybe; readonly type?: InputMaybe; @@ -2103,7 +2102,7 @@ export type TeamNodeFundraisingEntriesArgs = { export const TeamResolverAllKeys = { LegacyStatus: 'legacyStatus', - MarathonYear: 'marathonYear', + MarathonId: 'marathonId', Name: 'name', Type: 'type' } as const; @@ -2136,7 +2135,7 @@ export type TeamResolverKeyedStringFilterItem = { export const TeamResolverOneOfFilterKeys = { LegacyStatus: 'legacyStatus', - MarathonYear: 'marathonYear', + MarathonId: 'marathonId', Type: 'type' } as const; diff --git a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts index c924906f..dfe81b3b 100644 --- a/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts +++ b/packages/portal/src/elements/forms/team/edit/useTeamEditorForm.ts @@ -33,8 +33,6 @@ export function useTeamEditorForm( defaultValues: { name: teamData?.name ?? "", legacyStatus: teamData?.legacyStatus ?? null, - // TODO: Make this dynamic - marathonYear: teamData?.marathon.year ?? "DB24", type: teamData?.type ?? TeamType.Spirit, }, onSubmit: async (values) => { diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index b7d6bee6..b49e57ea 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -1,4 +1,5 @@ import { EditOutlined, EyeOutlined } from "@ant-design/icons"; +import { useMarathon } from "@config/marathonContext"; import { useListQuery } from "@hooks/useListQuery"; import { useMakeStringSearchFilterProps } from "@hooks/useMakeSearchFilterProps"; import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; @@ -47,10 +48,6 @@ export const TeamsTableFragment = graphql(/* GraphQL */ ` type name legacyStatus - marathon { - id - year - } totalPoints } `); @@ -73,17 +70,11 @@ export const TeamsTable = () => { initSorting: [{ field: "totalPoints", direction: SortDirection.desc }], }, { - allFields: [ - "name", - "type", - "legacyStatus", - "marathonYear", - "totalPoints", - ], + allFields: ["name", "type", "legacyStatus", "marathonId", "totalPoints"], dateFields: [], isNullFields: [], numericFields: ["totalPoints"], - oneOfFields: ["type", "marathonYear", "legacyStatus"], + oneOfFields: ["type", "marathonId", "legacyStatus"], stringFields: ["name"], } ); @@ -98,18 +89,21 @@ export const TeamsTable = () => { loadingMessage: "Loading teams...", }); + const marathonId = useMarathon()?.id; + useEffect(() => { if ( - queryOptions.oneOfFilters.filter((f) => f.field === "marathonYear") + queryOptions.oneOfFilters.filter((f) => f.field === "marathonId") .length === 0 ) { - // TODO: Extract the marathon filter from the table and integrate it with a global setting for marathon - updateFilter("marathonYear", { - field: "marathonYear", - value: ["DB24"], - }); + if (marathonId) { + updateFilter("marathonId", { + field: "marathonId", + value: [marathonId], + }); + } } - }, [queryOptions.oneOfFilters, updateFilter]); + }, [marathonId, queryOptions.oneOfFilters, updateFilter]); return (

    { } }, }, - { - title: "Marathon Year", - dataIndex: "marathonYear", - sorter: true, - filters: [ - { - text: "DanceBlue 2024", - value: "DB24", - }, - ], - }, { title: "Total Points", dataIndex: "totalPoints", @@ -248,7 +231,7 @@ export const TeamsTable = () => { | "name" | "type" | "legacyStatus" - | "marathonYear", + | "marathonId", direction: sort.order === "ascend" ? SortDirection.asc : SortDirection.desc, }); @@ -274,9 +257,9 @@ export const TeamsTable = () => { }); break; } - case "marathonYear": { - updateFilter("marathonYear", { - field: "marathonYear", + case "marathonId": { + updateFilter("marathonId", { + field: "marathonId", value: value.map((v) => v.toString()), }); break; diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index 3b9377ce..8aef1799 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -25,7 +25,7 @@ type TeamIsNullKey = (typeof teamIsNullKeys)[number]; const teamNumericKeys = ["totalPoints"] as const; type TeamNumericKey = (typeof teamNumericKeys)[number]; -const teamOneOfKeys = ["type", "marathonYear", "legacyStatus"] as const; +const teamOneOfKeys = ["type", "marathonId", "legacyStatus"] as const; type TeamOneOfKey = (typeof teamOneOfKeys)[number]; const teamStringKeys = ["name"] as const; @@ -44,7 +44,7 @@ export type TeamOrderKeys = | "createdAt" | "updatedAt" | "type" - | "marathonYear" + | "marathonId" | "legacyStatus" | "name" | "totalPoints"; diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index c82a7cca..594259cf 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -19,7 +19,7 @@ export function buildTeamOrder( switch (key) { case "totalPoints": case "type": - case "marathonYear": + case "marathonId": case "legacyStatus": case "name": case "createdAt": @@ -49,7 +49,7 @@ export function buildTeamWhere( where[filter.field] = dateFilterToPrisma(filter); break; } - case "marathonYear": { + case "marathonId": { where["marathon"] = { year: oneOfFilterToPrisma(filter), }; diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 4ab759c7..a5b4630a 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -1,7 +1,4 @@ -import type { - MarathonYearString, - OptionalToNullable, -} from "@ukdanceblue/common"; +import type { OptionalToNullable } from "@ukdanceblue/common"; import * as Common from "@ukdanceblue/common"; import { AccessControl, @@ -108,26 +105,23 @@ class SetTeamInput implements OptionalToNullable> { @Field(() => TeamLegacyStatus, { nullable: true }) legacyStatus!: TeamLegacyStatus | null; - @Field(() => String, { nullable: true }) - marathonYear!: MarathonYearString | null; - @Field(() => String, { nullable: true }) persistentIdentifier!: string | null; } @ArgsType() class ListTeamsArgs extends FilteredListQueryArgs< - "name" | "type" | "legacyStatus" | "marathonYear", + "name" | "type" | "legacyStatus" | "marathonId", "name", - "type" | "legacyStatus" | "marathonYear", + "type" | "legacyStatus" | "marathonId", never, never, never >("TeamResolver", { - all: ["name", "type", "legacyStatus", "marathonYear"], + all: ["name", "type", "legacyStatus", "marathonId"], string: ["name"], numeric: [], - oneOf: ["type", "marathonYear", "legacyStatus"], + oneOf: ["type", "marathonId", "legacyStatus"], }) { @Field(() => [TeamType], { nullable: true }) type!: [TeamType] | null; @@ -139,7 +133,7 @@ class ListTeamsArgs extends FilteredListQueryArgs< visibility!: [DbRole] | null; @Field(() => [String], { nullable: true }) - marathonYear!: MarathonYearString[] | null; + marathonId!: string[] | null; } @ObjectType("DbFundsTeamInfo", { implements: [Common.Node] }) @@ -193,14 +187,14 @@ export class TeamResolver { take: query.pageSize, onlyDemo: ctx.userData.authSource === AuthSource.Demo, legacyStatus: query.legacyStatus, - marathon: query.marathonYear?.map((year) => ({ year })), + marathon: query.marathonId?.map((marathonId) => ({ uuid: marathonId })), type: query.type, }), this.teamRepository.countTeams({ filters: query.filters, onlyDemo: ctx.userData.authSource === AuthSource.Demo, legacyStatus: query.legacyStatus, - marathon: query.marathonYear?.map((year) => ({ year })), + marathon: query.marathonId?.map((marathonId) => ({ uuid: marathonId })), type: query.type, }), ]); diff --git a/schema.graphql b/schema.graphql index d35410c0..8623a0bc 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1951,7 +1951,7 @@ type Query { """The is-null filters to apply to the query""" isNullFilters: [TeamResolverKeyedIsNullFilterItem!] legacyStatus: [TeamLegacyStatus!] - marathonYear: [String!] + marathonId: [String!] """The numeric filters to apply to the query""" numericFilters: Void @@ -2078,7 +2078,6 @@ input SetPointOpportunityInput { input SetTeamInput { legacyStatus: TeamLegacyStatus - marathonYear: String name: String persistentIdentifier: String type: TeamType @@ -2179,7 +2178,7 @@ type TeamNode implements Node { enum TeamResolverAllKeys { legacyStatus - marathonYear + marathonId name type } @@ -2221,7 +2220,7 @@ input TeamResolverKeyedStringFilterItem { enum TeamResolverOneOfFilterKeys { legacyStatus - marathonYear + marathonId type } From 3da25be152a16ecd378cbe427842930ea6400734 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 03:51:36 +0000 Subject: [PATCH 113/153] Update marathon config to save selected marathon in local storage --- packages/portal/src/config/marathon.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/portal/src/config/marathon.tsx b/packages/portal/src/config/marathon.tsx index 2ce0cdf3..6115397c 100644 --- a/packages/portal/src/config/marathon.tsx +++ b/packages/portal/src/config/marathon.tsx @@ -1,6 +1,6 @@ import { dateTimeFromSomething } from "@ukdanceblue/common"; import { graphql } from "@ukdanceblue/common/graphql-client-admin"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useQuery } from "urql"; import { marathonContext } from "./marathonContext"; @@ -43,6 +43,14 @@ export const MarathonConfigProvider = ({ localStorage.getItem(LocalStorageKeys.SelectedMarathon) || null ); + useEffect(() => { + if (marathonId) { + localStorage.setItem(LocalStorageKeys.SelectedMarathon, marathonId); + } else { + localStorage.removeItem(LocalStorageKeys.SelectedMarathon); + } + }, [marathonId]); + const [latestMarathonResult] = useQuery({ query: latestMarathonDocument }); const [selectedMarathonResult] = useQuery({ query: selectedMarathonDocument, From 9b73ae3dfbae42c97dcad5ab7001160fe9bae3e3 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 04:14:23 +0000 Subject: [PATCH 114/153] Update marathon config to save selected marathon in local storage --- .../portal/src/elements/forms/team/create/TeamCreator.tsx | 3 ++- packages/portal/src/elements/singletons/NavigationMenu.css | 4 ++++ packages/portal/src/elements/singletons/NavigationMenu.tsx | 3 +++ packages/portal/src/elements/tables/TeamsTable.tsx | 4 ++-- packages/server/src/repositories/team/teamRepositoryUtils.ts | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 packages/portal/src/elements/singletons/NavigationMenu.css diff --git a/packages/portal/src/elements/forms/team/create/TeamCreator.tsx b/packages/portal/src/elements/forms/team/create/TeamCreator.tsx index ccc14b79..57b11a78 100644 --- a/packages/portal/src/elements/forms/team/create/TeamCreator.tsx +++ b/packages/portal/src/elements/forms/team/create/TeamCreator.tsx @@ -1,3 +1,4 @@ +import { useMarathon } from "@config/marathonContext"; import { TanAntFormItem } from "@elements/components/form/TanAntFormItem"; import { useNavigate } from "@tanstack/react-router"; import { TeamLegacyStatus, TeamType } from "@ukdanceblue/common"; @@ -58,7 +59,7 @@ export function TeamCreator() { )} -

    Marathon Year: DB24

    +

    Marathon Year: {useMarathon()?.year}

    { onChange={(value) => setMarathon(value)} loading={loading} value={marathon?.id} + variant="borderless" > {marathons ? marathons.map((marathon) => ( diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index b49e57ea..d75e4991 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -93,8 +93,8 @@ export const TeamsTable = () => { useEffect(() => { if ( - queryOptions.oneOfFilters.filter((f) => f.field === "marathonId") - .length === 0 + queryOptions.oneOfFilters.find((f) => f.field === "marathonId") + ?.value[0] !== marathonId ) { if (marathonId) { updateFilter("marathonId", { diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index 594259cf..8e3726c7 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -51,7 +51,7 @@ export function buildTeamWhere( } case "marathonId": { where["marathon"] = { - year: oneOfFilterToPrisma(filter), + uuid: oneOfFilterToPrisma(filter), }; break; } From 9e34be55135aeaf67b7b4bc1cc5f2dc121dc4fde Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 04:22:13 +0000 Subject: [PATCH 115/153] Update LoginStateResolver to use ctx.authorization.dbRole instead of ctx.userData.authSource --- packages/server/src/resolvers/LoginState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index ef82d98b..0b62cc9e 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -29,7 +29,7 @@ export class LoginStateResolver { @Query(() => LoginState) loginState(@Ctx() ctx: Context.GraphQLContext): LoginState { return { - loggedIn: ctx.userData.authSource !== AuthSource.None, + loggedIn: ctx.authorization.dbRole !== DbRole.None, effectiveCommitteeRoles: ctx.authorization.committees, dbRole: ctx.authorization.dbRole, authSource: ctx.userData.authSource, From 9da2a2bb3c9d18f5ee5d32448b90697ce60e0f8e Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 18 Jun 2024 04:36:45 +0000 Subject: [PATCH 116/153] Refactor FeedNode initialization to use 'id' instead of 'uuid' --- packages/common/lib/api/resources/Feed.ts | 2 +- packages/server/src/repositories/feed/feedModelToResource.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/common/lib/api/resources/Feed.ts b/packages/common/lib/api/resources/Feed.ts index 814f16cb..aa3421c1 100644 --- a/packages/common/lib/api/resources/Feed.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -32,7 +32,7 @@ export class FeedNode extends TimestampedResource implements Node { } public static init(init: { - uuid: string; + id: string; title: string; textContent?: string | null | undefined; createdAt?: Date; diff --git a/packages/server/src/repositories/feed/feedModelToResource.ts b/packages/server/src/repositories/feed/feedModelToResource.ts index 3f39e820..e3bb6f8e 100644 --- a/packages/server/src/repositories/feed/feedModelToResource.ts +++ b/packages/server/src/repositories/feed/feedModelToResource.ts @@ -3,7 +3,7 @@ import { FeedNode } from "@ukdanceblue/common"; export function feedItemModelToResource(feedItem: FeedItem): FeedNode { return FeedNode.init({ - uuid: feedItem.uuid, + id: feedItem.uuid, title: feedItem.title, textContent: feedItem.textContent, createdAt: feedItem.createdAt, From 744f40eed90af4dde9ac48fe816a970221aaa784 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 19 Jun 2024 02:31:01 +0000 Subject: [PATCH 117/153] Rename FeedRepository --- .../repositories/feed/{feedRepository.ts => FeedRepository.ts} | 0 packages/server/src/resolvers/FeedResolver.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/server/src/repositories/feed/{feedRepository.ts => FeedRepository.ts} (100%) diff --git a/packages/server/src/repositories/feed/feedRepository.ts b/packages/server/src/repositories/feed/FeedRepository.ts similarity index 100% rename from packages/server/src/repositories/feed/feedRepository.ts rename to packages/server/src/repositories/feed/FeedRepository.ts diff --git a/packages/server/src/resolvers/FeedResolver.ts b/packages/server/src/resolvers/FeedResolver.ts index a0d78cd7..f5363685 100644 --- a/packages/server/src/resolvers/FeedResolver.ts +++ b/packages/server/src/resolvers/FeedResolver.ts @@ -18,8 +18,8 @@ import { import { Service } from "typedi"; import { FileManager } from "../lib/files/FileManager.js"; +import { FeedRepository } from "../repositories/feed/FeedRepository.js"; import { feedItemModelToResource } from "../repositories/feed/feedModelToResource.js"; -import { FeedRepository } from "../repositories/feed/feedRepository.js"; import { imageModelToResource } from "../repositories/image/imageModelToResource.js"; @InputType() From b6cef1b1d7ac058200324dbc4b4fa383fc5f7abc Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 02:29:51 +0000 Subject: [PATCH 118/153] Tweak logging code --- .devcontainer/devcontainer.json | 3 +- packages/server/src/environment.ts | 7 ++++ .../server/src/lib/logging/auditLogging.ts | 11 ++++--- packages/server/src/lib/logging/sqlLogging.ts | 5 +-- .../server/src/lib/logging/standardLogging.ts | 5 +-- .../src/resolvers/AdministrationResolver.ts | 32 +++++++++++++++++++ 6 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 packages/server/src/resolvers/AdministrationResolver.ts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d960e700..324bb95a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -57,7 +57,8 @@ "MS_OIDC_URL": "https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration", "SERVE_PATH": "/workspaces/monorepo/local-uploads", "UPLOAD_PATH": "/workspaces/monorepo/local-uploads", - "MAX_FILE_SIZE": "200" + "MAX_FILE_SIZE": "200", + "LOG_DIR": "/workspaces/monorepo/packages/server/logs" }, "customizations": { diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index b0442084..b6543d1d 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -170,3 +170,10 @@ export const uploadPath = UPLOAD_PATH; // Disable all authorization checks const { OVERRIDE_AUTH } = process.env; export const authorizationOverride = OVERRIDE_AUTH === "THIS IS DANGEROUS"; + +// Log directory +const { LOG_DIR } = process.env; +if (!LOG_DIR) { + throw new Error("LOG_DIR is not set"); +} +export const logDir = LOG_DIR; diff --git a/packages/server/src/lib/logging/auditLogging.ts b/packages/server/src/lib/logging/auditLogging.ts index 1eb38d79..2a24932e 100644 --- a/packages/server/src/lib/logging/auditLogging.ts +++ b/packages/server/src/lib/logging/auditLogging.ts @@ -1,7 +1,7 @@ import type { LeveledLogMethod, Logger } from "winston"; import { createLogger, format, transports } from "winston"; -import { isDevelopment } from "../../environment.js"; +import { isDevelopment, logDir } from "../../environment.js"; export interface AuditLogger extends Logger { /** @@ -52,10 +52,14 @@ export interface AuditLogger extends Logger { notice: never; } +export const auditLoggerFileName = "audit.log.json"; + const auditLogTransport = new transports.File({ - filename: "audit.log.json", + filename: auditLoggerFileName, + dirname: logDir, maxsize: 1_000_000, maxFiles: 3, + format: format.combine(format.timestamp(), format.json()), }); const dangerousConsoleTransport = new transports.Console({ @@ -76,9 +80,8 @@ const dangerousConsoleTransport = new transports.Console({ export const auditLogger = createLogger({ level: "secure", - silent: isDevelopment, + silent: false, transports: [auditLogTransport, dangerousConsoleTransport], - format: format.combine(format.timestamp(), format.json()), levels: { info: 0, dangerous: 2, diff --git a/packages/server/src/lib/logging/sqlLogging.ts b/packages/server/src/lib/logging/sqlLogging.ts index 42f04596..ece96446 100644 --- a/packages/server/src/lib/logging/sqlLogging.ts +++ b/packages/server/src/lib/logging/sqlLogging.ts @@ -1,12 +1,13 @@ import type winston from "winston"; import { createLogger, format, transports } from "winston"; -import { isDevelopment } from "../../environment.js"; +import { isDevelopment, logDir } from "../../environment.js"; const databaseLogTransport = new transports.File({ filename: "database.log", maxsize: 1_000_000, - maxFiles: 3, + maxFiles: 1, + dirname: logDir, }); interface SqlLogger extends winston.Logger { diff --git a/packages/server/src/lib/logging/standardLogging.ts b/packages/server/src/lib/logging/standardLogging.ts index 316f1725..81cc6983 100644 --- a/packages/server/src/lib/logging/standardLogging.ts +++ b/packages/server/src/lib/logging/standardLogging.ts @@ -1,7 +1,7 @@ import type winston from "winston"; import { createLogger, format, transports } from "winston"; -import { loggingLevel } from "../../environment.js"; +import { logDir, loggingLevel } from "../../environment.js"; export const SyslogLevels = { emerg: 0, @@ -64,6 +64,7 @@ const combinedLogTransport = new transports.File({ filename: "combined.log", maxsize: 1_000_000, maxFiles: 3, + dirname: logDir, }); export const logger = createLogger({ @@ -95,7 +96,7 @@ export const logger = createLogger({ */ export function logFatal(content: unknown) { // Logs the error and then crashes the server - + logger.emerg(String(content), () => process.exit(1)); } diff --git a/packages/server/src/resolvers/AdministrationResolver.ts b/packages/server/src/resolvers/AdministrationResolver.ts new file mode 100644 index 00000000..2b3e7f1e --- /dev/null +++ b/packages/server/src/resolvers/AdministrationResolver.ts @@ -0,0 +1,32 @@ +import { readFile } from "fs/promises"; +import { join } from "path"; + +import { AccessControl, AccessLevel } from "@ukdanceblue/common"; +import { FieldResolver, ObjectType, Query, Resolver } from "type-graphql"; + +import { logDir } from "../environment.js"; +import { auditLoggerFileName } from "../lib/logging/auditLogging.js"; + +@ObjectType() +export class Administration { + @FieldResolver(() => Boolean) + ok() { + return true; + } +} + +@Resolver(() => Administration) +export class AdministrationResolver { + @AccessControl({ accessLevel: AccessLevel.SuperAdmin }) + @Query(() => Administration) + administration(): Promise { + return Promise.resolve(new Administration()); + } + + @AccessControl({ accessLevel: AccessLevel.SuperAdmin }) + @Query(() => String) + async auditLog(): Promise { + const fileLookup = await readFile(join(logDir, auditLoggerFileName)); + return fileLookup.toString("utf8"); + } +} From b3da09f514678f17e818dc5bc636f8375093c85f Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 02:45:35 +0000 Subject: [PATCH 119/153] Add a timeout to dbfunds sync --- packages/server/src/lib/error/direct.ts | 17 +++++++++++++ .../src/lib/fundraising/DbFundsProvider.ts | 24 ++++++++++++++++--- .../lib/fundraising/FundraisingProvider.ts | 8 +++++-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/server/src/lib/error/direct.ts b/packages/server/src/lib/error/direct.ts index a81180b7..338807fe 100644 --- a/packages/server/src/lib/error/direct.ts +++ b/packages/server/src/lib/error/direct.ts @@ -48,3 +48,20 @@ export class NotFoundError extends ConcreteError { return undefined; } } + +export class TimeoutError extends ConcreteError { + readonly #what: string | null; + + constructor(what?: string) { + super(); + this.#what = what ?? null; + } + + get message(): string { + return `${this.#what ?? "A task"} took too long`; + } + + get expose() { + return false; + } +} diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 1038238f..4d32bfe0 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -1,6 +1,7 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import { DateTime } from "luxon"; import { Maybe, Result } from "true-myth"; +import { err } from "true-myth/result"; import { Inject, Service } from "typedi"; import { z } from "zod"; @@ -8,6 +9,7 @@ import { dbFundsApiKeyToken, dbFundsApiOriginToken, } from "../../environment.js"; +import { TimeoutError } from "../error/direct.js"; import { BasicError, toBasicError } from "../error/error.js"; import { HttpError } from "../error/http.js"; import { ConcreteResult } from "../error/result.js"; @@ -92,7 +94,11 @@ function teamEntriesPath( return `/api/report/teamentries/${dbNum}/${year}`; } -export type DBFundsFundraisingProviderError = HttpError | ZodError | BasicError; +export type DBFundsFundraisingProviderError = + | HttpError + | ZodError + | BasicError + | TimeoutError; @Service() export class DBFundsFundraisingProvider implements FundraisingProvider { @@ -107,19 +113,31 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { path: string | URL ): Promise> { let response: Response; + let timeout: ReturnType | undefined = undefined; try { const url = new URL(path, this.dbFundsApiOrigin); + const abort = new AbortController(); + timeout = setTimeout(() => { + abort.abort(); + }, 2500); response = await fetch(url, { headers: { "X-AuthToken": this.dbFundsApiKey, }, + signal: abort.signal, }); } catch (error) { - return Result.err(toBasicError(error)); + return err( + error instanceof Error && error.name === "AbortError" + ? new TimeoutError("Fetching data from DbFunds") + : toBasicError(error) + ); + } finally { + clearTimeout(timeout); } if (!response.ok) { - return Result.err(new HttpError(response.status)); + return err(new HttpError(response.status)); } return Result.ok(await response.json()); diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index 23815d9c..571532f7 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -2,6 +2,7 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; import type { Maybe } from "true-myth"; +import type { TimeoutError } from "../error/direct.js"; import type { JsError, UnknownError } from "../error/error.js"; import type { HttpError } from "../error/http.js"; import type { ConcreteResult } from "../error/result.js"; @@ -26,13 +27,16 @@ export interface FundraisingProvider { ): Promise< ConcreteResult< FundraisingTeam[], - HttpError | JsError | UnknownError + HttpError | JsError | UnknownError | TimeoutError > >; getTeamEntries( marathonYear: MarathonYearString, identifier: unknown ): Promise< - ConcreteResult + ConcreteResult< + FundraisingEntry[], + HttpError | JsError | UnknownError | TimeoutError + > >; } From 166475ac3a09c3255a830fd714019b089b345042 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 02:57:39 +0000 Subject: [PATCH 120/153] Fix tasks deps --- .vscode/tasks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 57931db0..9265cab8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -104,7 +104,7 @@ "problemMatcher": [], "label": "Server: Build", "detail": "yarn workspace @ukdanceblue/server run build", - "dependsOn": ["Server: Prisma Generate", "Common: Build"] + "dependsOn": ["Common: Build"] } ] } From 1afb2b5adeb45825c2775f9d6864e6cdd6829835 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 03:29:38 +0000 Subject: [PATCH 121/153] Start on temp fundraising on portal --- .../common/lib/graphql-client-admin/gql.ts | 5 ++ .../lib/graphql-client-admin/graphql.ts | 8 ++ packages/common/tsconfig.json | 2 +- .../portal/src/elements/tables/TeamsTable.tsx | 13 ++- .../single-team/view-team/ViewTeamPage.tsx | 38 +------- .../fundraising/ViewTeamFundraising.tsx | 86 +++++++++++++++++++ .../view-team/points/ViewTeamPoints.tsx | 42 +++++++++ .../view-team/teamPageDocument.tsx | 14 +++ packages/portal/src/routing/router.ts | 10 ++- packages/portal/src/routing/teamRoutes.ts | 14 +++ 10 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 packages/portal/src/pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising.tsx create mode 100644 packages/portal/src/pages/teams/spirit/single-team/view-team/points/ViewTeamPoints.tsx create mode 100644 packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 64f373be..a64b5677 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -86,6 +86,7 @@ const documents = { "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, "\n query ViewPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n": types.ViewPersonPageDocument, "\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n": types.EditTeamPageDocument, + "\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n": types.ViewTeamFundraisingDocumentDocument, "\n query ViewTeamPage($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n": types.ViewTeamPageDocument, }; @@ -395,6 +396,10 @@ export function graphql(source: "\n query ViewPersonPage($uuid: String!) {\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"): (typeof documents)["\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index bceec8d0..5f4b515e 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -2674,6 +2674,13 @@ export type EditTeamPageQuery = { readonly __typename?: 'Query', readonly team: & { ' $fragmentRefs'?: { 'TeamEditorFragmentFragment': TeamEditorFragmentFragment } } ) } }; +export type ViewTeamFundraisingDocumentQueryVariables = Exact<{ + teamUuid: Scalars['String']['input']; +}>; + + +export type ViewTeamFundraisingDocumentQuery = { readonly __typename?: 'Query', readonly team: { readonly __typename?: 'SingleTeamResponse', readonly data: { readonly __typename?: 'TeamNode', readonly fundraisingEntries: { readonly __typename?: 'ListFundraisingEntriesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'FundraisingEntryNode', readonly id: string, readonly amount: number, readonly donatedByText?: string | null, readonly donatedToText?: string | null, readonly donatedOn: Date | string, readonly assignments: ReadonlyArray<{ readonly __typename?: 'FundraisingAssignmentNode', readonly id: string, readonly amount: number, readonly person?: { readonly __typename?: 'PersonNode', readonly name?: string | null } | null }> }> } } } }; + export type ViewTeamPageQueryVariables = Exact<{ teamUuid: Scalars['String']['input']; }>; @@ -2760,4 +2767,5 @@ export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ViewTeamFundraisingDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamFundraisingDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fundraisingEntries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"donatedByText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedToText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json index 494ebb4d..21eba09e 100644 --- a/packages/common/tsconfig.json +++ b/packages/common/tsconfig.json @@ -3,7 +3,7 @@ "noEmit": false, /* Visit https://aka.ms/tsconfig to read more about this file */ /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + "incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */, // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ diff --git a/packages/portal/src/elements/tables/TeamsTable.tsx b/packages/portal/src/elements/tables/TeamsTable.tsx index d75e4991..40595615 100644 --- a/packages/portal/src/elements/tables/TeamsTable.tsx +++ b/packages/portal/src/elements/tables/TeamsTable.tsx @@ -1,4 +1,4 @@ -import { EditOutlined, EyeOutlined } from "@ant-design/icons"; +import { DollarOutlined, EditOutlined, EyeOutlined } from "@ant-design/icons"; import { useMarathon } from "@config/marathonContext"; import { useListQuery } from "@hooks/useListQuery"; import { useMakeStringSearchFilterProps } from "@hooks/useMakeSearchFilterProps"; @@ -180,12 +180,21 @@ export const TeamsTable = () => {
    + + + + + + + + + + + {data?.team.data.fundraisingEntries.data.map( + ({ + id, + donatedByText, + donatedToText, + donatedOn, + amount, + assignments, + }) => ( + + + + + + + + ) + )} + +
    Donated ByDonated ToDonated OnAmountAssigned To
    {donatedByText}{donatedToText}{donatedOn.toLocaleString()}${amount} +
    + {assignments.map(({ id, person, amount }) => ( +
    +
    {person?.name}
    +
    ${amount}
    +
    + ))} +
    +
    + + ); +} diff --git a/packages/portal/src/pages/teams/spirit/single-team/view-team/points/ViewTeamPoints.tsx b/packages/portal/src/pages/teams/spirit/single-team/view-team/points/ViewTeamPoints.tsx new file mode 100644 index 00000000..11c3ad7f --- /dev/null +++ b/packages/portal/src/pages/teams/spirit/single-team/view-team/points/ViewTeamPoints.tsx @@ -0,0 +1,42 @@ +import { PointEntryCreator } from "@elements/forms/point-entry/create/PointEntryCreator"; +import { PointEntryTable } from "@elements/tables/point-entry/PointEntryTable"; +import { useQueryStatusWatcher } from "@hooks/useQueryStatusWatcher"; +import { useParams } from "@tanstack/react-router"; +import { Flex } from "antd"; +import { useQuery } from "urql"; + +import { teamPageDocument } from "../teamPageDocument"; + +export function ViewTeamPoints() { + const { teamId: teamUuid } = useParams({ from: "/teams/$teamId/" }); + + const [{ fetching, data, error }, refetch] = useQuery({ + query: teamPageDocument, + variables: { teamUuid }, + }); + useQueryStatusWatcher({ + fetching, + error, + loadingMessage: "Loading point entries...", + }); + + return ( + +
    +

    Point Entries

    + +
    +
    +

    Create Point Entry

    + refetch({ requestPolicy: "network-only" })} + /> +
    +
    + ); +} diff --git a/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx b/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx new file mode 100644 index 00000000..259cb745 --- /dev/null +++ b/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx @@ -0,0 +1,14 @@ +import { graphql } from "@ukdanceblue/common/graphql-client-admin"; + +export const teamPageDocument = graphql(/* GraphQL */ ` + query ViewTeamPage($teamUuid: String!) { + team(uuid: $teamUuid) { + data { + ...TeamViewerFragment + pointEntries { + ...PointEntryTableFragment + } + } + } + } +`); diff --git a/packages/portal/src/routing/router.ts b/packages/portal/src/routing/router.ts index 5b28a48d..891ac893 100644 --- a/packages/portal/src/routing/router.ts +++ b/packages/portal/src/routing/router.ts @@ -46,6 +46,8 @@ import { } from "./personRouter"; import { rootRoute } from "./rootRoute"; import { + ViewTeamFundraisingRoute, + ViewTeamPointsRoute, createTeamRoute, editTeamRoute, singleTeamRoute, @@ -63,7 +65,13 @@ const routeTree = rootRoute.addChildren([ teamsRoute.addChildren([ teamsTableRoute, createTeamRoute, - singleTeamRoute.addChildren([editTeamRoute, viewTeamRoute]), + singleTeamRoute.addChildren([ + editTeamRoute, + viewTeamRoute.addChildren([ + ViewTeamFundraisingRoute, + ViewTeamPointsRoute, + ]), + ]), ]), peopleRoute.addChildren([ peopleTableRoute, diff --git a/packages/portal/src/routing/teamRoutes.ts b/packages/portal/src/routing/teamRoutes.ts index e3587bb9..029fd0b6 100644 --- a/packages/portal/src/routing/teamRoutes.ts +++ b/packages/portal/src/routing/teamRoutes.ts @@ -3,6 +3,8 @@ import { ListTeamsPage } from "@pages/teams/spirit/list-teams/ListTeamsPage"; import { SingleTeamPage } from "@pages/teams/spirit/single-team/SingleTeamPage"; import { EditTeamPage } from "@pages/teams/spirit/single-team/edit-team/EditTeamPage"; import { ViewTeamPage } from "@pages/teams/spirit/single-team/view-team/ViewTeamPage"; +import { ViewTeamFundraising } from "@pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising"; +import { ViewTeamPoints } from "@pages/teams/spirit/single-team/view-team/points/ViewTeamPoints"; import { Route } from "@tanstack/react-router"; import { teamsRoute } from "./baseRoutes"; @@ -36,3 +38,15 @@ export const viewTeamRoute = new Route({ getParentRoute: () => singleTeamRoute, component: ViewTeamPage, }); + +export const ViewTeamFundraisingRoute = new Route({ + path: "fundraising", + getParentRoute: () => viewTeamRoute, + component: ViewTeamFundraising, +}); + +export const ViewTeamPointsRoute = new Route({ + path: "points", + getParentRoute: () => viewTeamRoute, + component: ViewTeamPoints, +}); From 41091e9f17deec86eff1471181b21150656e4524 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 03:49:17 +0000 Subject: [PATCH 122/153] Update compose file --- compose.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compose.yaml b/compose.yaml index 751eff10..0df92ffa 100644 --- a/compose.yaml +++ b/compose.yaml @@ -17,8 +17,6 @@ services: build: context: . dockerfile: ./packages/server/Dockerfile - ports: - - 8080:8000 networks: - danceblue depends_on: @@ -32,6 +30,11 @@ services: NODE_ENV: development APPLICATION_HOST: server DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue + portal: + container_name: portal + build: + context: ./packages/portal + dockerfile: ./packages/portal/Dockerfile networks: danceblue: From 395142c4e342174bf6069c1d1b03cd71d6427247 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Thu, 27 Jun 2024 16:44:37 +0000 Subject: [PATCH 123/153] Some more work on compose file --- compose.yaml | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/compose.yaml b/compose.yaml index 0df92ffa..cd699826 100644 --- a/compose.yaml +++ b/compose.yaml @@ -2,40 +2,54 @@ services: postgres: + container_name: danceblue-app-database-${SUBDOMAIN:?error} image: postgres:latest environment: POSTGRES_USER: danceblue POSTGRES_PASSWORD: danceblue POSTGRES_DB: danceblue networks: - - danceblue + - database attach: false volumes: - ./compose-volumes/postgres:/var/lib/postgresql/data server: - container_name: server + container_name: danceblue-app-server-${SUBDOMAIN:?error} build: context: . dockerfile: ./packages/server/Dockerfile networks: - - danceblue + - database + - proxy depends_on: - postgres env_file: ./packages/server/.env environment: + NODE_ENV: ${NODE_ENV:-production} + APPLICATION_PORT: 8000 + MS_OIDC_URL: https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration + SERVE_PATH: /data/local-uploads + UPLOAD_PATH: /data/local-uploads + MAX_FILE_SIZE: 200 + LOG_DIR: /data/logs DB_HOST: postgres DB_NAME: danceblue DB_UNAME: danceblue DB_PWD: danceblue - NODE_ENV: development - APPLICATION_HOST: server + APPLICATION_HOST: danceblue-app-server-${SUBDOMAIN:?error} DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue + volumes: + - danceblue-app-server-${SUBDOMAIN:?error}-data:/data:rw portal: - container_name: portal + container_name: danceblue-app-portal-${SUBDOMAIN:?error} + networks: + - proxy build: context: ./packages/portal dockerfile: ./packages/portal/Dockerfile networks: - danceblue: - driver: bridge + database: + proxy: + external: true + name: proxy From 95f520c8399ff135bfac8fd48ede145dededd014 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 29 Jun 2024 02:45:44 +0000 Subject: [PATCH 124/153] Add GlobalIdScalar custom scalar type for GraphQL API --- new-desing.graphql | 574 -------------------- packages/common/lib/api/scalars/GlobalId.ts | 100 ++++ 2 files changed, 100 insertions(+), 574 deletions(-) delete mode 100644 new-desing.graphql create mode 100644 packages/common/lib/api/scalars/GlobalId.ts diff --git a/new-desing.graphql b/new-desing.graphql deleted file mode 100644 index ffd2795e..00000000 --- a/new-desing.graphql +++ /dev/null @@ -1,574 +0,0 @@ -# Custom Scalars - -""" -A cursor for use in paginating through collections of data. Cursors are opaque strings that are -intended to be used by clients to paginate through a connection. Clients should not attempt to -destructure or parse the cursor string, as the format may change at any time. -""" -scalar Cursor - -""" -This is a special scalar that is used to represent the unique identifier of a node. It is serialized -as a string and parsed from a string. It is guaranteed to be unique across all nodes in the system, -and is used to identify nodes in the Relay specification. For the purposes of this schema, it is -an opaque string that can be used to identify a node. The client should never attempt to parse or -destructure this value, as the format may change at any time. -""" -scalar NodeID - -# GraphQL Scalars - -""" -A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format -outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates -and times using the Gregorian calendar.This scalar is serialized to a string in ISO 8601 format and -parsed from a string in ISO 8601 format. -""" -scalar DateTimeISO - -""" -A string representing a duration conforming to the ISO8601 standard, such as P1W1DT13H23M34S. -""" -scalar Duration - -""" -A field whose value conforms to the standard internet email address format as specified in HTML -Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. -""" -scalar EmailAddress - @specifiedBy( - url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address" - ) - -""" -Integers that will have a value of 0 or more. -""" -scalar NonNegativeInt - -""" -Integers that will have a value greater than 0. -""" -scalar PositiveInt - -""" -A field whose value conforms to the standard URL format as specified in RFC3986: https://www.ietf.org/rfc/rfc3986.txt. -""" -scalar URL - -""" -Represents NULL values -""" -scalar Void - -scalar UUID - -# Enums - -""" -The source of authentication -""" -enum AuthSource { - Anonymous - Demo - LinkBlue - None -} - -""" -Roles within a committee -""" -enum CommitteeRole { - Chair - Coordinator - Member -} - -""" -DanceBlue roles -""" -enum DbRole { - Committee - None - Public - UKY -} - -""" -The position of a member on a team -""" -enum MembershipPositionType { - Captain - Member -} - -enum SortDirection { - ASCENDING - DESCENDING -} - -""" -New Team vs Returning Team -""" -enum TeamLegacyStatus { - DemoTeam - NewTeam - ReturningTeam -} - -""" -Types of teams -""" -enum PointType { - Morale - Spirit -} - -enum ErrorCode { - INTERNAL_ERROR -} - -""" -All the tabs the app can show -""" -enum MobileAppTab { - Home - Events - Explore - Teams - Marathon - DBMoments - Info -} - -# Re-used Types - -type PageInfo { - """ - hasPreviousPage is used to indicate whether more edges exist prior to the set defined by the - clients arguments. If the client is paginating with last/before, then the server must return - true if prior edges exist, otherwise false. If the client is paginating with first/after, - then the client may return true if edges prior to after exist, if it can do so efficiently, - otherwise may return false. - """ - hasPreviousPage: Boolean! - """ - hasNextPage is used to indicate whether more edges exist following the set defined by the clients - arguments. If the client is paginating with first/after, then the server must return true if - further edges exist, otherwise false. If the client is paginating with last/before, then the - client may return true if edges further from before exist, if it can do so efficiently, otherwise - may return false. - """ - hasNextPage: Boolean! - """ - startCursor is simply an opaque value that refers to the first position in a connection. It is - used by the client to request the first set of edges in a connection. The server must return - the cursor that corresponds to the first element in the connection. - """ - startCursor: Cursor - """ - endCursor is simply an opaque value that refers to the last position in a connection. It is - used by the client to request the last set of edges in a connection. The server must return - the cursor that corresponds to the last element in the connection. - """ - endCursor: Cursor -} - -type Error { - """ - A specific error code to identify the error - """ - code: ErrorCode! - """ - A human readable error message - """ - message: String! - """ - A message that should be presented to the user - """ - alert: String - """ - Development information about the error. should not be sent to untrusted clients (i.e. production environments) - """ - debugInfo: String -} - -type IntervalISO { - """ - The beginning of the interval - """ - start: DateTimeISO! - """ - The end of the interval - """ - end: DateTimeISO! - - """ - The ISO formatted interval - """ - iso8601: String - - """ - The duration of the interval - """ - duration: Duration - - """ - Whether the interval is empty, meaning the start and end are the same - """ - isEmpty: Boolean -} - -# Interfaces - -interface Node { - id: NodeID! -} - -interface Edge { - cursor: Cursor! - node: Node! -} - -interface Errorable { - errors: [Error!]! -} - -interface Connection implements Errorable { - totalCount: NonNegativeInt! - edges: [Edge!]! - pageInfo: PageInfo! - errors: [Error!]! -} - -interface Resource implements Errorable { - node: Node! - errors: [Error!]! -} - -interface Result implements Errorable { - node: Node - errors: [Error!]! -} - -# Resources - -type Configuration { - uuid: UUID! - - key: String! - value: String! - validAfter: DateTimeISO - validUntil: DateTimeISO - - setBy: Person - - updatedAt: DateTimeISO - createdAt: DateTimeISO -} - -type MobileAppConfiguration { # TODO - shownTabs: [MobileAppTab!]! - fancyTab: MobileAppTab - allowedLoginTypes: [AuthSource!]! -} - -type Device { - uuid: UUID! - - lastLoggedInUser: Person - lastLogin: DateTimeISO - notificationDeliveries( - page: PositiveInt = 1 - pageSize: NonNegativeInt = 10 - ): [NotificationDelivery!]! - - createdAt: DateTimeISO - updatedAt: DateTimeISO -} - -type Event { - uuid: UUID! - - title: String! - summary: String - description: String - images: [Image!]! - location: String - occurrences: [IntervalISO!]! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type Feed { - uuid: UUID! - - title: String! - image: Image - textContent: String - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type Image { - uuid: UUID! - - url: URL - alt: String - mimeType: String! - thumbHash: String - height: NonNegativeInt! - width: NonNegativeInt! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -""" -Describes a set of teams whose points are compared -""" -type Leaderboard { - uuid: UUID! - - """ - An ordered list of teams - """ - teams: [Team!]! - - # The filters applied to this leaderboard - legacyStatus: TeamLegacyStatus - """ - If true: only committee teams are included, if false: only non-committee teams are included, if null: all teams are included - """ - committee: Boolean - pointType: PointType! - - """ - A short user-friendly description of the leaderboard - """ - description: String -} - -type MarathonHour { - uuid: UUID! - - title: String! - details: String - durationInfo: String! - - shownStartingAt: DateTimeISO! - - updatedBy: Person - createdAt: DateTimeISO - createdBy: Person - updatedAt: DateTimeISO -} - -type Marathon { - uuid: UUID! - - hours: [MarathonHour!]! - - """ - A four digit year - """ - year: String! - interval: IntervalISO! - - allSpiritTeamsLeaderboard: Leaderboard! - returningSpiritTeamsLeaderboard: Leaderboard! - newSpiritTeamsLeaderboard: Leaderboard! - committeeSpiritTeamsLeaderboard: Leaderboard! - nonCommitteeSpiritTeamsLeaderboard: Leaderboard! - moraleLeaderboard: Leaderboard! - - communityDevelopmentCommittee: Committee! - corporateCommittee: Committee! - dancerRelationsCommittee: Committee! - familyRelationsCommittee: Committee! - fundraisingCommittee: Committee! - marketingCommittee: Committee! - miniMarathonsCommittee: Committee! - operationsCommittee: Committee! - programmingCommittee: Committee! - techCommittee: Committee! - viceCommittee: Committee! - overallCommittee: Committee! - - teams: [Team!]! - - updatedBy: Person - createdAt: DateTimeISO - createdBy: Person - updatedAt: DateTimeISO -} - -type Membership { - uuid: UUID! - - person: Person! - team: Team! - - position: MembershipPositionType! - - updatedBy: Person - createdAt: DateTimeISO - createdBy: Person - updatedAt: DateTimeISO -} - -type NotificationDelivery { - uuid: UUID! - - notification: Notification! - - """ - A unique identifier corresponding the group of notifications this was sent to Expo with. - """ - chunkUuid: String - - """ - Any error message returned by Expo when sending the notification. - """ - deliveryError: String - - """ - The time the server received a delivery receipt from the user. - """ - receiptCheckedAt: DateTimeISO - - """ - The time the server sent the notification to Expo for delivery. - """ - sentAt: DateTimeISO - - updatedAt: DateTimeISO - createdAt: DateTimeISO -} - -type Notification { - uuid: UUID! - - title: String! - body: String! - - sentBy: Person - """ - The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. - """ - sendAt: DateTimeISO - - """ - The time the server started sending the notification. - """ - startedSendingAt: DateTimeISO - url: URL - - deliveryCount: NonNegativeInt! - deliveryIssue: String - deliveryIssueAcknowledgedAt: DateTimeISO - deliveryIssueCount: NonNegativeInt! - - updatedBy: Person - createdAt: DateTimeISO - createdBy: Person - updatedAt: DateTimeISO -} - -type Person { - uuid: UUID! - - teams: [Membership!]! - primaryCommittee: Committee - primaryCommitteeRole: CommitteeRole - committees: [Committee!]! - - dbRole: DbRole! - - name: String - email: String! - linkblue: String - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type PointEntry { - uuid: UUID! - - personFrom: Person - team: Team! - - comment: String - pointOpportunity: PointOpportunity - points: NonNegativeInt! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type PointOpportunity { - uuid: UUID! - - event: Event - - marathon: Marathon! - - name: String! - opportunityDate: DateTimeISO - type: PointType! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type Team { - uuid: UUID! - - members: [Membership!]! - pointEntries: [PointEntry!]! - - marathon: Marathon! - - legacyStatus: TeamLegacyStatus! - type: PointType! - name: String! - totalPoints: NonNegativeInt! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} - -type Committee { - uuid: UUID! - - team: Team! - - chairs: [Person!]! - coordinators: [Person!]! - members: [Person!]! - allMembers: [Person!]! - - parentCommittee: Committee - subCommittees: [Committee!]! - - updatedBy: Person - updatedAt: DateTimeISO - createdBy: Person - createdAt: DateTimeISO -} diff --git a/packages/common/lib/api/scalars/GlobalId.ts b/packages/common/lib/api/scalars/GlobalId.ts new file mode 100644 index 00000000..38fb997b --- /dev/null +++ b/packages/common/lib/api/scalars/GlobalId.ts @@ -0,0 +1,100 @@ +import { GraphQLScalarType, Kind } from "graphql"; + +import { + UTF8ArrToStr, + arrayToBase64String, + base64StringToArray, + strToUTF8Arr, +} from "../../utility/primitive/base64.js"; + +export const GlobalIdScalar = new GraphQLScalarType< + { typename: string; id: string }, + string +>({ + name: "GlobalId", + description: "GlobalId custom scalar type", + extensions: {}, + parseValue(value): { typename: string; id: string } { + if (typeof value === "object") { + if ( + value && + typeof value === "object" && + "typename" in value && + "id" in value + ) { + const { typename, id } = value; + if (typeof typename !== "string" || typeof id !== "string") { + throw new TypeError( + "GlobalIdScalar can only parse objects with typename and id as strings" + ); + } + return { typename, id }; + } else { + throw new TypeError( + "GlobalIdScalar can only parse objects with typename and id" + ); + } + } else if (typeof value === "string") { + const plain = UTF8ArrToStr(base64StringToArray(value)); + const [typename, id, ...rest] = plain.split(":"); + if (rest.length > 0) { + throw new TypeError( + "GlobalIdScalar can only parse strings with one colon" + ); + } + if (!typename || !id) { + throw new TypeError( + "GlobalIdScalar can only parse strings with a colon" + ); + } + return { typename, id }; + } else { + throw new TypeError("GlobalIdScalar can only parse strings or objects"); + } + }, + serialize(value): string { + if (typeof value === "object") { + if ( + value && + typeof value === "object" && + "typename" in value && + "id" in value + ) { + const { typename, id } = value; + if (typeof typename !== "string" || typeof id !== "string") { + throw new TypeError( + "GlobalIdScalar can only serialize objects with typename and id as strings" + ); + } + return arrayToBase64String(strToUTF8Arr(`${typename}:${id}`)); + } else { + throw new TypeError( + "GlobalIdScalar can only serialize objects with typename and id" + ); + } + } else { + throw new TypeError("GlobalIdScalar can only serialize objects"); + } + }, + parseLiteral(ast): { typename: string; id: string } { + if (ast.kind === Kind.STRING) { + const plain = UTF8ArrToStr(base64StringToArray(ast.value)); + const [typename, id, ...rest] = plain.split(":"); + if (rest.length > 0) { + throw new TypeError( + "GlobalIdScalar can only parse strings with one colon" + ); + } + if (!typename || !id) { + throw new TypeError( + "GlobalIdScalar can only parse strings with a colon" + ); + } + return { typename, id }; + } else { + throw new TypeError( + "GlobalIdScalar can only parse literal string values" + ); + } + }, +}); From 57edfe091ba3de44f2e7a9890870d7d15df8540d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 29 Jun 2024 03:45:29 +0000 Subject: [PATCH 125/153] Refactor code to use GlobalIdScalar for GraphQL API --- packages/common/lib/api/relay.ts | 8 ++-- .../common/lib/api/resources/Committee.ts | 22 ++++++---- .../common/lib/api/resources/Configuration.ts | 20 ++++++--- packages/common/lib/api/resources/Device.ts | 19 +++++--- packages/common/lib/api/resources/Event.ts | 36 ++++++++++++---- packages/common/lib/api/resources/Feed.ts | 12 +++--- .../common/lib/api/resources/Fundraising.ts | 23 ++++++---- packages/common/lib/api/resources/Image.ts | 24 ++++++++--- packages/common/lib/api/resources/Marathon.ts | 12 +++--- .../common/lib/api/resources/MarathonHour.ts | 16 ++++--- .../common/lib/api/resources/Membership.ts | 14 +++--- .../common/lib/api/resources/Notification.ts | 43 ++++++++++++++----- packages/common/lib/api/resources/Person.ts | 25 ++++------- .../common/lib/api/resources/PointEntry.ts | 20 ++++++--- .../lib/api/resources/PointOpportunity.ts | 21 ++++++--- packages/common/lib/api/resources/Resource.ts | 27 +++++++----- packages/common/lib/api/resources/Team.ts | 21 ++++++--- packages/common/lib/api/scalars/GlobalId.ts | 5 +++ packages/common/lib/authentication/jwt.ts | 2 +- 19 files changed, 243 insertions(+), 127 deletions(-) diff --git a/packages/common/lib/api/relay.ts b/packages/common/lib/api/relay.ts index 4b61763a..bc8314c3 100644 --- a/packages/common/lib/api/relay.ts +++ b/packages/common/lib/api/relay.ts @@ -1,7 +1,9 @@ -import { Field, ID, InterfaceType, ObjectType } from "type-graphql"; +import { Field, InterfaceType, ObjectType } from "type-graphql"; import { Errorable, ResourceError } from "./resourceError.js"; import { CursorScalar } from "./scalars/Cursor.js"; +import type { GlobalId } from "./scalars/GlobalId.js"; +import { GlobalIdScalar } from "./scalars/GlobalId.js"; @ObjectType() export class PageInfo { @@ -36,8 +38,8 @@ export class PageInfo { @InterfaceType() export abstract class Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; } @InterfaceType() export abstract class Edge { diff --git a/packages/common/lib/api/resources/Committee.ts b/packages/common/lib/api/resources/Committee.ts index 3b5776f1..5ea0d78d 100644 --- a/packages/common/lib/api/resources/Committee.ts +++ b/packages/common/lib/api/resources/Committee.ts @@ -1,26 +1,30 @@ -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { CommitteeIdentifier } from "../../authorization/structures.js"; import { Node } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node] }) export class CommitteeNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => CommitteeIdentifier) identifier!: CommitteeIdentifier; - static init(init: { id: string; identifier: CommitteeIdentifier }) { - return this.doInit({ - id: init.id, - identifier: init.identifier, - }); + static init(init: { + id: string; + identifier: CommitteeIdentifier; + updatedAt?: Date | null; + createdAt?: Date | null; + }) { + return this.createInstance().withValues(init); } public getUniqueId(): string { - return this.id; + return this.id.id; } } diff --git a/packages/common/lib/api/resources/Configuration.ts b/packages/common/lib/api/resources/Configuration.ts index 9d35a50f..a93127fd 100644 --- a/packages/common/lib/api/resources/Configuration.ts +++ b/packages/common/lib/api/resources/Configuration.ts @@ -1,9 +1,11 @@ import { DateTimeISOResolver } from "graphql-scalars"; import { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; /* @@ -21,8 +23,8 @@ to have additional validation logic in the future. implements: [Node], }) export class ConfigurationNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) key!: string; @@ -46,8 +48,16 @@ export class ConfigurationNode extends TimestampedResource implements Node { return this.key; } - public static init(init: Partial) { - return ConfigurationNode.doInit(init); + public static init(init: { + id: string; + key: string; + value: string; + validAfter?: Date | null; + validUntil?: Date | null; + createdAt?: Date | null; + updatedAt?: Date | null; + }) { + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Device.ts b/packages/common/lib/api/resources/Device.ts index ba027773..ea641a52 100644 --- a/packages/common/lib/api/resources/Device.ts +++ b/packages/common/lib/api/resources/Device.ts @@ -1,15 +1,17 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node] }) export class DeviceNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => DateTimeISOResolver, { nullable: true }) public lastLogin?: Date | null; @@ -18,11 +20,16 @@ export class DeviceNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return DeviceNode.doInit(init); + public static init(init: { + id: string; + lastLogin?: Date | null; + createdAt: Date; + updatedAt: Date; + }) { + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index cc53b619..05be58a9 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -1,6 +1,8 @@ import { Field, ID, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { IntervalISO } from "../types/IntervalISO.js"; import { Resource, TimestampedResource } from "./Resource.js"; @@ -9,8 +11,8 @@ import { Resource, TimestampedResource } from "./Resource.js"; implements: [Node], }) export class EventNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => [EventOccurrenceNode]) occurrences!: EventOccurrenceNode[]; @Field(() => String) @@ -23,11 +25,19 @@ export class EventNode extends TimestampedResource implements Node { location!: string | null; public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return EventNode.doInit(init); + public static init(init: { + id: string; + title: string; + summary?: string | null; + description?: string | null; + location?: string | null; + updatedAt?: Date | null; + createdAt?: Date | null; + }) { + return this.createInstance().withValues(init); } } @@ -36,18 +46,26 @@ export class EventNode extends TimestampedResource implements Node { }) export class EventOccurrenceNode extends Resource { @Field(() => ID) - uuid!: string; + id!: string; @Field(() => IntervalISO) interval!: IntervalISO; @Field(() => Boolean) fullDay!: boolean; public getUniqueId(): string { - return this.uuid; + return this.id; } - public static init(init: Partial) { - return EventOccurrenceNode.doInit(init); + public static init(init: { + id: string; + interval: IntervalISO; + fullDay: boolean; + }) { + const resource = this.createInstance(); + resource.id = init.id; + resource.interval = init.interval; + resource.fullDay = init.fullDay; + return resource; } } diff --git a/packages/common/lib/api/resources/Feed.ts b/packages/common/lib/api/resources/Feed.ts index aa3421c1..e143f2e3 100644 --- a/packages/common/lib/api/resources/Feed.ts +++ b/packages/common/lib/api/resources/Feed.ts @@ -1,6 +1,8 @@ -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; // TODO: Expand this to include more types of feed items @@ -18,8 +20,8 @@ import { TimestampedResource } from "./Resource.js"; implements: [Node], }) export class FeedNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) title!: string; @@ -28,7 +30,7 @@ export class FeedNode extends TimestampedResource implements Node { textContent?: string | null | undefined; public getUniqueId(): string { - return this.id; + return this.id.id; } public static init(init: { @@ -38,7 +40,7 @@ export class FeedNode extends TimestampedResource implements Node { createdAt?: Date; updatedAt?: Date; }) { - return FeedNode.doInit(init); + return FeedNode.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts index 4a6b87ca..05008372 100644 --- a/packages/common/lib/api/resources/Fundraising.ts +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -2,10 +2,12 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Maybe } from "true-myth"; import { nothing, of } from "true-myth/maybe"; -import { Field, Float, ID, ObjectType } from "type-graphql"; +import { Field, Float, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @@ -13,8 +15,8 @@ import { TimestampedResource } from "./Resource.js"; implements: [Node], }) export class FundraisingEntryNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String, { nullable: true, name: "donatedByText" }) private _donatedByText!: string | null; get donatedByText(): Maybe { @@ -40,7 +42,7 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { amount!: number; public getUniqueId(): string { - return this.id; + return this.id.id; } public static init(init: { @@ -53,7 +55,10 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { updatedAt: Date; }) { const node = new FundraisingEntryNode(); - node.id = init.id; + node.id = { + id: init.id, + typename: "FundraisingEntryNode", + }; node.donatedByText = init.donatedByText == null ? nothing() @@ -88,13 +93,13 @@ export class FundraisingAssignmentNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => Float) amount!: number; public getUniqueId(): string { - return this.id; + return this.id.id; } public static init(init: { @@ -103,7 +108,7 @@ export class FundraisingAssignmentNode createdAt: Date; updatedAt: Date; }) { - return FundraisingAssignmentNode.doInit(init); + return FundraisingAssignmentNode.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Image.ts b/packages/common/lib/api/resources/Image.ts index 721cdcbe..ee02444e 100644 --- a/packages/common/lib/api/resources/Image.ts +++ b/packages/common/lib/api/resources/Image.ts @@ -1,15 +1,17 @@ import { URLResolver } from "graphql-scalars"; -import { Field, ID, Int, ObjectType } from "type-graphql"; +import { Field, Int, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) export class ImageNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => URLResolver, { nullable: true }) url!: URL | null; @@ -30,11 +32,21 @@ export class ImageNode extends TimestampedResource implements Node { height!: number; public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return ImageNode.doInit(init); + public static init(init: { + id: string; + url?: URL | null; + mimeType: string; + thumbHash?: string | null; + alt?: string | null; + width: number; + height: number; + updatedAt?: Date | null; + createdAt?: Date | null; + }) { + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Marathon.ts b/packages/common/lib/api/resources/Marathon.ts index 046e05fe..7dfcc267 100644 --- a/packages/common/lib/api/resources/Marathon.ts +++ b/packages/common/lib/api/resources/Marathon.ts @@ -1,17 +1,19 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) export class MarathonNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) year!: string; @Field(() => DateTimeISOResolver, { nullable: true }) @@ -40,7 +42,7 @@ export class MarathonNode extends TimestampedResource implements Node { createdAt?: Date | null; updatedAt?: Date | null; }): MarathonNode { - return this.doInit({ + return this.createInstance().withValues({ id, year, startDate, @@ -51,7 +53,7 @@ export class MarathonNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.id.id; } } diff --git a/packages/common/lib/api/resources/MarathonHour.ts b/packages/common/lib/api/resources/MarathonHour.ts index 300cc8e9..324cc866 100644 --- a/packages/common/lib/api/resources/MarathonHour.ts +++ b/packages/common/lib/api/resources/MarathonHour.ts @@ -1,17 +1,19 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) export class MarathonHourNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) title!: string; @Field(() => String, { nullable: true }) @@ -25,7 +27,7 @@ export class MarathonHourNode extends TimestampedResource implements Node { durationInfo!: string; static init({ - id: uuid, + id, title, details, shownStartingAt, @@ -41,8 +43,8 @@ export class MarathonHourNode extends TimestampedResource implements Node { createdAt?: Date | null; updatedAt?: Date | null; }): MarathonHourNode { - return this.doInit({ - uuid, + return this.createInstance().withValues({ + id, title, details, shownStartingAt, @@ -53,7 +55,7 @@ export class MarathonHourNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.id.id; } } diff --git a/packages/common/lib/api/resources/Membership.ts b/packages/common/lib/api/resources/Membership.ts index 2f4aab19..6b0ce6e3 100644 --- a/packages/common/lib/api/resources/Membership.ts +++ b/packages/common/lib/api/resources/Membership.ts @@ -1,10 +1,12 @@ -import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; +import { Field, ObjectType, registerEnumType } from "type-graphql"; import { CommitteeIdentifier, CommitteeRole, } from "../../authorization/structures.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; export const MembershipPositionType = { @@ -23,14 +25,14 @@ registerEnumType(MembershipPositionType, { implements: [Node], }) export class MembershipNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => MembershipPositionType) position!: MembershipPositionType; public getUniqueId(): string { - return this.id; + return this.id.id; } public static init(init: { @@ -39,7 +41,7 @@ export class MembershipNode extends TimestampedResource implements Node { createdAt?: Date | null; updatedAt?: Date | null; }) { - return MembershipNode.doInit(init); + return MembershipNode.createInstance().withValues(init); } } @@ -61,7 +63,7 @@ export class CommitteeMembershipNode extends MembershipNode implements Node { createdAt?: Date | null; updatedAt?: Date | null; }) { - return CommitteeMembershipNode.doInit(init); + return CommitteeMembershipNode.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Notification.ts b/packages/common/lib/api/resources/Notification.ts index 12743300..9eff5e7f 100644 --- a/packages/common/lib/api/resources/Notification.ts +++ b/packages/common/lib/api/resources/Notification.ts @@ -1,19 +1,21 @@ import { DateTimeISOResolver, URLResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { AccessControl } from "../../authorization/accessControl.js"; import { AccessLevel } from "../../authorization/structures.js"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) export class NotificationNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) title!: string; @@ -55,11 +57,22 @@ export class NotificationNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return NotificationNode.doInit(init); + public static init(init: { + id: string; + title: string; + body: string; + url?: URL | null; + deliveryIssue?: string | null; + deliveryIssueAcknowledgedAt?: Date | null; + sendAt?: Date | null; + startedSendingAt?: Date | null; + createdAt: Date; + updatedAt: Date; + }) { + return NotificationNode.createInstance().withValues(init); } } @@ -73,8 +86,8 @@ export class NotificationDeliveryNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => Date, { nullable: true, @@ -108,11 +121,19 @@ export class NotificationDeliveryNode deliveryError?: string | null; public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return NotificationDeliveryNode.doInit(init); + public static init(init: { + id: string; + sentAt?: Date | null; + receiptCheckedAt?: Date | null; + chunkUuid?: string | null; + deliveryError?: string | null; + createdAt: Date; + updatedAt: Date; + }) { + return NotificationDeliveryNode.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Person.ts b/packages/common/lib/api/resources/Person.ts index c0efc59a..e10ae760 100644 --- a/packages/common/lib/api/resources/Person.ts +++ b/packages/common/lib/api/resources/Person.ts @@ -1,7 +1,9 @@ -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { DbRole } from "../../authorization/structures.js"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @@ -9,8 +11,8 @@ import { TimestampedResource } from "./Resource.js"; implements: [Node], }) export class PersonNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String, { nullable: true }) name!: string | null; @Field(() => String) @@ -21,11 +23,11 @@ export class PersonNode extends TimestampedResource implements Node { dbRole!: DbRole; public getUniqueId(): string { - return this.id; + return this.id.id; } public static init(init: { - uuid: string; + id: string; name?: string | null; email: string; linkblue?: string | null; @@ -33,18 +35,7 @@ export class PersonNode extends TimestampedResource implements Node { createdAt?: Date | null; updatedAt?: Date | null; }) { - const resource = PersonNode.doInit({ - id: init.uuid, - email: init.email, - }); - - resource.name = init.name ?? null; - resource.linkblue = init.linkblue ?? null; - resource.dbRole = init.dbRole ?? DbRole.None; - resource.createdAt = init.createdAt ?? null; - resource.updatedAt = init.updatedAt ?? null; - - return resource; + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/PointEntry.ts b/packages/common/lib/api/resources/PointEntry.ts index 37ca8d0f..e1703f49 100644 --- a/packages/common/lib/api/resources/PointEntry.ts +++ b/packages/common/lib/api/resources/PointEntry.ts @@ -1,25 +1,33 @@ -import { Field, ID, Int, ObjectType } from "type-graphql"; +import { Field, Int, ObjectType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; @ObjectType({ implements: [Node], }) export class PointEntryNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String, { nullable: true }) comment!: string | null; @Field(() => Int) points!: number; public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return PointEntryNode.doInit(init); + public static init(init: { + id: string; + comment?: string | null; + points: number; + createdAt?: Date | null; + updatedAt?: Date | null; + }) { + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/PointOpportunity.ts b/packages/common/lib/api/resources/PointOpportunity.ts index 192857af..a8ec9894 100644 --- a/packages/common/lib/api/resources/PointOpportunity.ts +++ b/packages/common/lib/api/resources/PointOpportunity.ts @@ -1,9 +1,11 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Field, ID, ObjectType } from "type-graphql"; +import { Field, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; import { Node } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; import { TeamType } from "./Team.js"; @@ -12,8 +14,8 @@ import { TeamType } from "./Team.js"; implements: [Node], }) export class PointOpportunityNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) name!: string; @Field(() => TeamType) @@ -25,10 +27,17 @@ export class PointOpportunityNode extends TimestampedResource implements Node { } public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return PointOpportunityNode.doInit(init); + public static init(init: { + id: string; + name: string; + type: TeamType; + opportunityDate: Date | null; + createdAt: Date; + updatedAt: Date; + }) { + return this.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/resources/Resource.ts b/packages/common/lib/api/resources/Resource.ts index 64c74c66..82f7a94e 100644 --- a/packages/common/lib/api/resources/Resource.ts +++ b/packages/common/lib/api/resources/Resource.ts @@ -3,6 +3,7 @@ import { Field, ObjectType } from "type-graphql"; import type { Class } from "utility-types"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; +import { GlobalId } from "../scalars/GlobalId.js"; @ObjectType() export abstract class Resource { @@ -19,24 +20,30 @@ export abstract class Resource { throw new Error(`Method not implemented by subclass.`); } - protected static doInit(this: Class, init: object): R { - const instance = new this(); - Object.assign(instance, init); - return instance; + protected static createInstance(this: Class): R { + return new this(); + } + + protected withValues( + this: R, + values: D + ): R { + this.id = { id: values.id, typename: this.constructor.name }; + return this; } } @ObjectType() export abstract class TimestampedResource extends Resource { @Field(() => Date, { nullable: true }) - createdAt?: Date | null; - get createdAtDateTime(): DateTime | null { - return dateTimeFromSomething(this.createdAt ?? null); + createdAt!: Date; + get createdAtDateTime(): DateTime { + return dateTimeFromSomething(this.createdAt); } @Field(() => Date, { nullable: true }) - updatedAt?: Date | null; - get updatedAtDateTime(): DateTime | null { - return dateTimeFromSomething(this.updatedAt ?? null); + updatedAt!: Date; + get updatedAtDateTime(): DateTime { + return dateTimeFromSomething(this.updatedAt); } } diff --git a/packages/common/lib/api/resources/Team.ts b/packages/common/lib/api/resources/Team.ts index 00084528..7fcfdd40 100644 --- a/packages/common/lib/api/resources/Team.ts +++ b/packages/common/lib/api/resources/Team.ts @@ -1,6 +1,8 @@ -import { Field, ID, ObjectType, registerEnumType } from "type-graphql"; +import { Field, ObjectType, registerEnumType } from "type-graphql"; import { Node, createNodeClasses } from "../relay.js"; +import type { GlobalId } from "../scalars/GlobalId.js"; +import { GlobalIdScalar } from "../scalars/GlobalId.js"; import { TimestampedResource } from "./Resource.js"; export const TeamType = { @@ -34,8 +36,8 @@ registerEnumType(TeamLegacyStatus, { implements: [Node], }) export class TeamNode extends TimestampedResource implements Node { - @Field(() => ID) - id!: string; + @Field(() => GlobalIdScalar) + id!: GlobalId; @Field(() => String) name!: string; @Field(() => TeamType) @@ -44,11 +46,18 @@ export class TeamNode extends TimestampedResource implements Node { legacyStatus!: TeamLegacyStatus; public getUniqueId(): string { - return this.id; + return this.id.id; } - public static init(init: Partial) { - return TeamNode.doInit(init); + public static init(init: { + id: string; + name: string; + type: TeamType; + legacyStatus: TeamLegacyStatus; + createdAt?: Date | null; + updatedAt?: Date | null; + }) { + return TeamNode.createInstance().withValues(init); } } diff --git a/packages/common/lib/api/scalars/GlobalId.ts b/packages/common/lib/api/scalars/GlobalId.ts index 38fb997b..8a202ea3 100644 --- a/packages/common/lib/api/scalars/GlobalId.ts +++ b/packages/common/lib/api/scalars/GlobalId.ts @@ -7,6 +7,11 @@ import { strToUTF8Arr, } from "../../utility/primitive/base64.js"; +export interface GlobalId { + typename: string; + id: string; +} + export const GlobalIdScalar = new GraphQLScalarType< { typename: string; id: string }, string diff --git a/packages/common/lib/authentication/jwt.ts b/packages/common/lib/authentication/jwt.ts index 070760bd..c939b698 100644 --- a/packages/common/lib/authentication/jwt.ts +++ b/packages/common/lib/authentication/jwt.ts @@ -11,7 +11,7 @@ export function makeUserData( authSource: AuthSource ): UserData { return { - userId: person.id, + userId: person.id.id, authSource, }; } From c0f8ab9b7b6ec2c4d4ac603092d7c49e919de308 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 29 Jun 2024 04:02:25 +0000 Subject: [PATCH 126/153] Refactor code to use GlobalIdScalar for GraphQL API --- packages/common/lib/api/resources/Event.ts | 1 + packages/common/lib/api/resources/index.ts | 1 + .../server/src/jobs/garbageCollectLogins.ts | 2 +- .../LoginFlowSession.ts | 0 .../event/eventModelToResource.ts | 2 +- .../person/personModelToResource.ts | 2 +- .../src/resolvers/ConfigurationResolver.ts | 6 ++- .../server/src/resolvers/DeviceResolver.ts | 41 +++++++++------- .../server/src/resolvers/EventResolver.ts | 22 ++++++--- packages/server/src/resolvers/FeedResolver.ts | 4 +- .../FundraisingAssignmentResolver.ts | 18 ++++--- .../src/resolvers/FundraisingEntryResolver.ts | 12 +++-- .../server/src/resolvers/ImageResolver.ts | 22 ++++++--- .../src/resolvers/MarathonHourResolver.ts | 31 +++++++----- .../server/src/resolvers/MarathonResolver.ts | 25 ++++++---- .../src/resolvers/MembershipResolver.ts | 9 ++-- .../src/resolvers/NotificationResolver.ts | 44 ++++++++++------- .../server/src/resolvers/PersonResolver.ts | 44 ++++++++++------- .../src/resolvers/PointEntryResolver.ts | 22 +++++---- .../src/resolvers/PointOpportunityResolver.ts | 16 +++--- packages/server/src/resolvers/TeamResolver.ts | 49 +++++++++++-------- packages/server/src/routes/api/auth/login.ts | 2 +- .../src/routes/api/auth/oidcCallback.ts | 2 +- 23 files changed, 222 insertions(+), 155 deletions(-) rename packages/server/src/{resolvers => repositories}/LoginFlowSession.ts (100%) diff --git a/packages/common/lib/api/resources/Event.ts b/packages/common/lib/api/resources/Event.ts index 05be58a9..d1286df8 100644 --- a/packages/common/lib/api/resources/Event.ts +++ b/packages/common/lib/api/resources/Event.ts @@ -36,6 +36,7 @@ export class EventNode extends TimestampedResource implements Node { location?: string | null; updatedAt?: Date | null; createdAt?: Date | null; + occurrences: EventOccurrenceNode[]; }) { return this.createInstance().withValues(init); } diff --git a/packages/common/lib/api/resources/index.ts b/packages/common/lib/api/resources/index.ts index de0c2d59..4627557a 100644 --- a/packages/common/lib/api/resources/index.ts +++ b/packages/common/lib/api/resources/index.ts @@ -1,3 +1,4 @@ +export * from "../scalars/GlobalId.js"; export { AuthIdPairResource as AuthIdPairNode } from "../types/AuthIdPair.js"; export { EffectiveCommitteeRole } from "../types/EffectiveCommitteeRole.js"; export { IntervalISO } from "../types/IntervalISO.js"; diff --git a/packages/server/src/jobs/garbageCollectLogins.ts b/packages/server/src/jobs/garbageCollectLogins.ts index 82d03176..04d20281 100644 --- a/packages/server/src/jobs/garbageCollectLogins.ts +++ b/packages/server/src/jobs/garbageCollectLogins.ts @@ -2,7 +2,7 @@ import Cron from "croner"; import { Container } from "typedi"; import { logger } from "../lib/logging/standardLogging.js"; -import { LoginFlowSessionRepository } from "../resolvers/LoginFlowSession.js"; +import { LoginFlowSessionRepository } from "../repositories/LoginFlowSession.js"; export const garbageCollectLoginFlowSessions = new Cron( "0 0 */6 * * *", diff --git a/packages/server/src/resolvers/LoginFlowSession.ts b/packages/server/src/repositories/LoginFlowSession.ts similarity index 100% rename from packages/server/src/resolvers/LoginFlowSession.ts rename to packages/server/src/repositories/LoginFlowSession.ts diff --git a/packages/server/src/repositories/event/eventModelToResource.ts b/packages/server/src/repositories/event/eventModelToResource.ts index f5510c1b..7b95ba8f 100644 --- a/packages/server/src/repositories/event/eventModelToResource.ts +++ b/packages/server/src/repositories/event/eventModelToResource.ts @@ -25,7 +25,7 @@ export function eventOccurrenceModelToResource( occurrenceModel: EventOccurrence ): EventOccurrenceNode { return EventOccurrenceNode.init({ - uuid: occurrenceModel.uuid, + id: occurrenceModel.uuid, interval: IntervalISO.init(occurrenceModel.date, occurrenceModel.endDate), fullDay: occurrenceModel.fullDay, }); diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index d71974ae..d96d19ee 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -12,7 +12,7 @@ export async function personModelToResource( }); return PersonNode.init({ - uuid: person.uuid, + id: person.uuid, name: person.name, email: person.email, linkblue: person.linkblue, diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index 6652c652..1ea6c39d 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -1,9 +1,11 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessLevel, ConfigurationNode, DetailedError, ErrorCode, + GlobalIdScalar, SortDirection, dateTimeFromSomething, } from "@ukdanceblue/common"; @@ -161,9 +163,9 @@ export class ConfigurationResolver { @AccessControl({ accessLevel: AccessLevel.Admin }) @Mutation(() => DeleteConfigurationResponse, { name: "deleteConfiguration" }) async delete( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { - const row = await this.configurationRepository.deleteConfiguration(uuid); + const row = await this.configurationRepository.deleteConfiguration(id); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Configuration not found"); diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 426f9628..7fec3b70 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -1,8 +1,10 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { DetailedError, DeviceNode, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, NotificationDeliveryNode, PersonNode, SortDirection, @@ -124,8 +126,10 @@ export class DeviceResolver { ) {} @Query(() => GetDeviceByUuidResponse, { name: "device" }) - async getByUuid(@Arg("uuid") uuid: string): Promise { - const row = await this.deviceRepository.getDeviceByUuid(uuid); + async getByUuid( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.deviceRepository.getDeviceByUuid(id); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Device not found"); @@ -180,19 +184,21 @@ export class DeviceResolver { } @Mutation(() => DeleteDeviceResponse, { name: "deleteDevice" }) - async delete(@Arg("uuid") uuid: string): Promise { - await this.deviceRepository.deleteDevice({ uuid }); + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + await this.deviceRepository.deleteDevice({ uuid: id }); - auditLogger.normal("Device deleted", { uuid }); + auditLogger.normal("Device deleted", { uuid: id }); return DeleteDeviceResponse.newOk(true); } @FieldResolver(() => PersonNode, { nullable: true }) async lastLoggedInUser( - @Root() device: DeviceNode + @Root() { id: { id } }: DeviceNode ): Promise { - const user = await this.deviceRepository.getLastLoggedInUser(device.id); + const user = await this.deviceRepository.getLastLoggedInUser(id); return user == null ? null @@ -201,10 +207,10 @@ export class DeviceResolver { @FieldResolver(() => [NotificationDeliveryNode]) async notificationDeliveries( - @Root() device: DeviceNode, + @Root() { id: { id } }: DeviceNode, @Args(() => NotificationDeliveriesArgs) query: NotificationDeliveriesArgs ): Promise { - const row = await this.deviceRepository.getDeviceByUuid(device.id); + const row = await this.deviceRepository.getDeviceByUuid(id); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Device not found"); @@ -221,16 +227,13 @@ export class DeviceResolver { } const rows = - await this.deviceRepository.findNotificationDeliveriesForDevice( - device.id, - { - skip: - query.page != null && query.pageSize != null - ? (query.page - 1) * query.pageSize - : undefined, - take: query.pageSize, - } - ); + await this.deviceRepository.findNotificationDeliveriesForDevice(id, { + skip: + query.page != null && query.pageSize != null + ? (query.page - 1) * query.pageSize + : undefined, + take: query.pageSize, + }); return rows.map(notificationDeliveryModelToResource); } diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index 593c6810..f791295b 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -1,4 +1,5 @@ import type { Prisma } from "@prisma/client"; +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessLevel, @@ -6,6 +7,7 @@ import { ErrorCode, EventNode, FilteredListQueryArgs, + GlobalIdScalar, ImageNode, IntervalISO, SortDirection, @@ -200,8 +202,10 @@ export class EventResolver { private readonly fileManager: FileManager ) {} @Query(() => GetEventByUuidResponse, { name: "event" }) - async getByUuid(@Arg("uuid") uuid: string): Promise { - const row = await this.eventRepository.findEventByUnique({ uuid }); + async getByUuid( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.eventRepository.findEventByUnique({ uuid: id }); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Event not found"); @@ -280,14 +284,16 @@ export class EventResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => DeleteEventResponse, { name: "deleteEvent" }) - async delete(@Arg("uuid") uuid: string): Promise { - const row = await this.eventRepository.deleteEvent({ uuid }); + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.eventRepository.deleteEvent({ uuid: id }); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Event not found"); } - auditLogger.sensitive("Event deleted", { uuid }); + auditLogger.sensitive("Event deleted", { uuid: id }); return DeleteEventResponse.newOk(true); } @@ -295,11 +301,11 @@ export class EventResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => SetEventResponse, { name: "setEvent" }) async set( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetEventInput ): Promise { const row = await this.eventRepository.updateEvent( - { uuid }, + { uuid: id }, { title: input.title, summary: input.summary, @@ -396,7 +402,7 @@ export class EventResolver { @FieldResolver(() => [ImageNode]) async images(@Root() event: EventNode): Promise { const rows = await this.eventImageRepository.findEventImagesByEventUnique({ - uuid: event.id, + uuid: event.id.id, }); return Promise.all( diff --git a/packages/server/src/resolvers/FeedResolver.ts b/packages/server/src/resolvers/FeedResolver.ts index f5363685..cb736d13 100644 --- a/packages/server/src/resolvers/FeedResolver.ts +++ b/packages/server/src/resolvers/FeedResolver.ts @@ -130,8 +130,8 @@ export class FeedResolver { } @FieldResolver(() => ImageNode, { nullable: true }) - async image(@Root() { id: uuid }: FeedNode) { - const row = await this.feedRepository.getFeedItemImage({ uuid }); + async image(@Root() { id: { id } }: FeedNode) { + const row = await this.feedRepository.getFeedItemImage({ uuid: id }); if (row == null) { return null; } diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 370c3644..0c90d356 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -1,3 +1,4 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessControlParam, @@ -5,6 +6,7 @@ import { CommitteeRole, FundraisingAssignmentNode, FundraisingEntryNode, + GlobalIdScalar, MembershipPositionType, PersonNode, } from "@ukdanceblue/common"; @@ -61,7 +63,7 @@ export class FundraisingAssignmentResolver { @AccessControl(fundraisingAccess) @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( - @Arg("id") id: string + @Arg("id", () => GlobalIdScalar) { id }: GlobalId ): Promise>> { const assignment = await this.fundraisingEntryRepository.findAssignmentByUnique({ @@ -91,7 +93,7 @@ export class FundraisingAssignmentResolver { @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async updateFundraisingAssignment( - @Arg("id") id: string, + @Arg("id", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") { amount }: UpdateFundraisingAssignmentInput ): Promise>> { const assignment = await this.fundraisingEntryRepository.updateAssignment( @@ -105,7 +107,7 @@ export class FundraisingAssignmentResolver { @AccessControl(fundraisingAccess) @Mutation(() => FundraisingAssignmentNode) async deleteFundraisingAssignment( - @Arg("id") id: string + @Arg("id", () => GlobalIdScalar) { id }: GlobalId ): Promise>> { const assignment = await this.fundraisingEntryRepository.deleteAssignment({ uuid: id, @@ -115,7 +117,7 @@ export class FundraisingAssignmentResolver { } @AccessControl(globalFundraisingAccessParam, { - custom: async (_, { teamMemberships }, { id }) => { + custom: async (_, { teamMemberships }, { id: { id } }) => { const personRepository = Container.get(PersonRepository); const memberships = (await personRepository.findMembershipsOfPerson( @@ -146,10 +148,10 @@ export class FundraisingAssignmentResolver { "The person assigned to this assignment, only null when access is denied", }) async person( - @Root() assignment: FundraisingAssignmentNode + @Root() { id: { id } }: FundraisingAssignmentNode ): Promise>> { const person = await this.fundraisingEntryRepository.getPersonForAssignment( - { uuid: assignment.id } + { uuid: id } ); return person.map((person) => personModelToResource(person, this.personRepository) @@ -158,10 +160,10 @@ export class FundraisingAssignmentResolver { @FieldResolver(() => FundraisingEntryNode) async entry( - @Root() assignment: FundraisingAssignmentNode + @Root() { id: { id } }: FundraisingAssignmentNode ): Promise>> { const entry = await this.fundraisingEntryRepository.getEntryForAssignment({ - uuid: assignment.id, + uuid: id, }); return entry.map(fundraisingEntryModelToNode); } diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 0248a121..6a696182 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -1,4 +1,5 @@ import { CommitteeRole } from "@prisma/client"; +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessControlParam, @@ -6,6 +7,7 @@ import { FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, + GlobalIdScalar, MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; @@ -91,7 +93,9 @@ export class FundraisingEntryResolver { @AccessControl(globalFundraisingAccessParam) @Query(() => FundraisingEntryNode) - async fundraisingEntry(@Arg("id") id: string): Promise { + async fundraisingEntry( + @Arg("id", () => GlobalIdScalar) { id }: GlobalId + ): Promise { const entry = await this.fundraisingEntryRepository.findEntryByUnique({ uuid: id, }); @@ -148,7 +152,7 @@ export class FundraisingEntryResolver { // 2. The captain of the team the entry is associated with { custom: async ( - { id }, + { id: { id } }, { teamMemberships, userData: { userId } } ): Promise => { if (userId == null) { @@ -185,11 +189,11 @@ export class FundraisingEntryResolver { ) @FieldResolver(() => [FundraisingAssignmentNode]) async assignments( - @Root() entry: FundraisingEntryNode + @Root() { id: { id } }: FundraisingEntryNode ): Promise { const assignments = await this.fundraisingEntryRepository.getAssignmentsForEntry({ - uuid: entry.id, + uuid: id, }); if (assignments.isErr) { throw new CatchableConcreteError(assignments.error); diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index 7f5b9cba..4db13aca 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -1,11 +1,13 @@ import { MIMEType } from "node:util"; +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessLevel, DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, ImageNode, SortDirection, } from "@ukdanceblue/common"; @@ -87,8 +89,10 @@ export class ImageResolver { ) {} @Query(() => GetImageByUuidResponse, { name: "image" }) - async getByUuid(@Arg("uuid") uuid: string): Promise { - const result = await this.imageRepository.findImageByUnique({ uuid }); + async getByUuid( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const result = await this.imageRepository.findImageByUnique({ uuid: id }); if (result == null) { throw new DetailedError(ErrorCode.NotFound, "Image not found"); @@ -175,12 +179,12 @@ export class ImageResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => ImageNode, { name: "setImageAltText" }) async setAltText( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("alt") alt: string ): Promise { const result = await this.imageRepository.updateImage( { - uuid, + uuid: id, }, { alt, @@ -199,13 +203,13 @@ export class ImageResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => ImageNode, { name: "setImageUrl" }) async setImageUrl( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("url", () => URLResolver) url: URL ): Promise { const { mime, thumbHash, width, height } = await handleImageUrl(url); const result = await this.imageRepository.updateImage( { - uuid, + uuid: id, }, { width, @@ -243,8 +247,10 @@ export class ImageResolver { @Mutation(() => ImageNode, { name: "setImageUrl" }) @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => DeleteImageResponse, { name: "deleteImage" }) - async delete(@Arg("uuid") uuid: string): Promise { - const result = await this.imageRepository.deleteImage({ uuid }); + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const result = await this.imageRepository.deleteImage({ uuid: id }); if (result == null) { throw new DetailedError(ErrorCode.NotFound, "Image not found"); diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index 0fc8eed7..16b97f13 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -1,7 +1,9 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, ImageNode, MarathonHourNode, } from "@ukdanceblue/common"; @@ -101,10 +103,10 @@ export class MarathonHourResolver { ) {} @Query(() => MarathonHourNode) - async marathonHour(@Arg("uuid") uuid: string) { + async marathonHour(@Arg("uuid", () => GlobalIdScalar) { id }: GlobalId) { const marathonHour = await this.marathonHourRepository.findMarathonHourByUnique({ - uuid, + uuid: id, }); if (marathonHour == null) { throw new DetailedError(ErrorCode.NotFound, "MarathonHour not found"); @@ -136,8 +138,8 @@ export class MarathonHourResolver { } @FieldResolver(() => [ImageNode]) - async mapImages(@Root() marathonHour: MarathonHourNode) { - return this.marathonHourRepository.getMaps({ uuid: marathonHour.id }); + async mapImages(@Root() { id: { id } }: MarathonHourNode) { + return this.marathonHourRepository.getMaps({ uuid: id }); } @Mutation(() => MarathonHourNode) @@ -154,11 +156,11 @@ export class MarathonHourResolver { @Mutation(() => MarathonHourNode) async setMarathonHour( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetMarathonHourInput ) { const marathonHour = await this.marathonHourRepository.updateMarathonHour( - { uuid }, + { uuid: id }, input ); if (marathonHour == null) { @@ -168,9 +170,11 @@ export class MarathonHourResolver { } @Mutation(() => VoidResolver) - async deleteMarathonHour(@Arg("uuid") uuid: string) { + async deleteMarathonHour( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ) { const marathonHour = await this.marathonHourRepository.deleteMarathonHour({ - uuid, + uuid: id, }); if (marathonHour == null) { throw new DetailedError(ErrorCode.NotFound, "MarathonHour not found"); @@ -178,9 +182,12 @@ export class MarathonHourResolver { } @Mutation(() => MarathonHourNode) - async addMap(@Arg("uuid") uuid: string, @Arg("imageUuid") imageUuid: string) { + async addMap( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, + @Arg("imageUuid") imageUuid: string + ) { const marathonHour = await this.marathonHourRepository.addMap( - { uuid }, + { uuid: id }, { uuid: imageUuid } ); if (marathonHour == null) { @@ -191,11 +198,11 @@ export class MarathonHourResolver { @Mutation(() => VoidResolver) async removeMap( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("imageUuid") imageUuid: string ) { const marathonHour = await this.marathonHourRepository.removeMap( - { uuid }, + { uuid: id }, { uuid: imageUuid } ); if (marathonHour == null) { diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index ec110307..73392e3f 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -1,8 +1,10 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { CommitteeIdentifier, DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, MarathonHourNode, MarathonNode, SortDirection, @@ -93,9 +95,9 @@ export class MarathonResolver ) {} @Query(() => MarathonNode) - async marathon(@Arg("uuid") uuid: string) { + async marathon(@Arg("uuid", () => GlobalIdScalar) { id }: GlobalId) { const marathon = await this.marathonRepository.findMarathonByUnique({ - uuid, + uuid: id, }); if (marathon == null) { throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); @@ -166,11 +168,11 @@ export class MarathonResolver @Mutation(() => MarathonNode) async setMarathon( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetMarathonInput ) { const marathon = await this.marathonRepository.updateMarathon( - { uuid }, + { uuid: id }, input ); if (marathon == null) { @@ -180,24 +182,27 @@ export class MarathonResolver } @Mutation(() => VoidResolver) - async deleteMarathon(@Arg("uuid") uuid: string) { - const marathon = await this.marathonRepository.deleteMarathon({ uuid }); + async deleteMarathon(@Arg("uuid", () => GlobalIdScalar) { id }: GlobalId) { + const marathon = await this.marathonRepository.deleteMarathon({ uuid: id }); if (marathon == null) { throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); } } @FieldResolver(() => [MarathonHourNode]) - async hours(@Root() marathon: MarathonNode) { + async hours(@Root() { id: { id } }: MarathonNode) { const rows = await this.marathonRepository.getMarathonHours({ - uuid: marathon.id, + uuid: id, }); return rows.map(marathonHourModelToResource); } - async #committeeTeam(committee: CommitteeIdentifier, marathon: MarathonNode) { + async #committeeTeam( + committee: CommitteeIdentifier, + { id: { id } }: MarathonNode + ) { const result = await this.committeeRepository.getCommitteeTeam(committee, { - uuid: marathon.id, + uuid: id, }); if (result == null) { throw new DetailedError( diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 5ec5e618..54d4e539 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -12,7 +12,6 @@ import { MembershipRepository } from "../repositories/membership/MembershipRepos import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; - @Resolver(() => MembershipNode) @Service() export class MembershipResolver { @@ -22,9 +21,9 @@ export class MembershipResolver { ) {} @FieldResolver(() => PersonNode) - async person(@Root() membership: MembershipNode): Promise { + async person(@Root() { id: { id } }: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( - { uuid: membership.id }, + { uuid: id }, { person: true, } @@ -38,9 +37,9 @@ export class MembershipResolver { } @FieldResolver(() => TeamNode) - async team(@Root() membership: MembershipNode): Promise { + async team(@Root() { id: { id } }: MembershipNode): Promise { const row = await this.membershipRepository.findMembershipByUnique( - { uuid: membership.id }, + { uuid: id }, { team: true, } diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 865faade..ed8feeba 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -1,10 +1,12 @@ import type { NotificationError } from "@prisma/client"; +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessLevel, DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, NotificationDeliveryNode, NotificationNode, SortDirection, @@ -230,10 +232,10 @@ export class NotificationResolver { }) @Query(() => GetNotificationByUuidResponse, { name: "notification" }) async getByUuid( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const row = await this.notificationRepository.findNotificationByUnique({ - uuid, + uuid: id, }); if (row == null) { @@ -369,9 +371,11 @@ export class NotificationResolver { name: "sendNotification", description: "Send a notification immediately.", }) - async send(@Arg("uuid") uuid: string): Promise { + async send( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { const databaseNotification = - await this.notificationRepository.findNotificationByUnique({ uuid }); + await this.notificationRepository.findNotificationByUnique({ uuid: id }); if (databaseNotification == null) { throw new DetailedError(ErrorCode.NotFound, "Notification not found"); @@ -398,11 +402,11 @@ export class NotificationResolver { name: "scheduleNotification", }) async schedule( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("sendAt") sendAt: Date ): Promise { const notification = - await this.notificationRepository.findNotificationByUnique({ uuid }); + await this.notificationRepository.findNotificationByUnique({ uuid: id }); if (notification == null) { throw new DetailedError(ErrorCode.NotFound, "Notification not found"); @@ -432,10 +436,10 @@ export class NotificationResolver { name: "acknowledgeDeliveryIssue", }) async acknowledgeDeliveryIssue( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const notification = - await this.notificationRepository.findNotificationByUnique({ uuid }); + await this.notificationRepository.findNotificationByUnique({ uuid: id }); if (notification == null) { throw new DetailedError(ErrorCode.NotFound, "Notification not found"); @@ -463,10 +467,10 @@ export class NotificationResolver { name: "abortScheduledNotification", }) async abortScheduled( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const notification = - await this.notificationRepository.findNotificationByUnique({ uuid }); + await this.notificationRepository.findNotificationByUnique({ uuid: id }); if (notification == null) { throw new DetailedError(ErrorCode.NotFound, "Notification not found"); @@ -499,7 +503,7 @@ export class NotificationResolver { }) @Mutation(() => DeleteNotificationResponse, { name: "deleteNotification" }) async delete( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("force", { nullable: true, description: @@ -508,7 +512,7 @@ export class NotificationResolver { force?: boolean ): Promise { const notification = - await this.notificationRepository.findNotificationByUnique({ uuid }); + await this.notificationRepository.findNotificationByUnique({ uuid: id }); if (notification == null) { throw new DetailedError(ErrorCode.NotFound, "Notification not found"); @@ -532,8 +536,12 @@ export class NotificationResolver { accessLevel: AccessLevel.CommitteeChairOrCoordinator, }) @FieldResolver(() => Int, { name: "deliveryCount" }) - async deliveryCount(@Root() { id: uuid }: NotificationNode): Promise { - return this.notificationRepository.countDeliveriesForNotification({ uuid }); + async deliveryCount( + @Root() { id: { id } }: NotificationNode + ): Promise { + return this.notificationRepository.countDeliveriesForNotification({ + uuid: id, + }); } @AccessControl({ @@ -543,11 +551,11 @@ export class NotificationResolver { name: "deliveryIssueCount", }) async deliveryIssueCount( - @Root() { id: uuid }: NotificationNode + @Root() { id: { id } }: NotificationNode ): Promise { const issues = await this.notificationRepository.countFailedDeliveriesForNotification({ - uuid, + uuid: id, }); const retVal = new NotificationDeliveryIssueCount(); @@ -568,11 +576,11 @@ export class NotificationDeliveryResolver { name: "notification", }) async getNotificationForDelivery( - @Root() { id: uuid }: NotificationDeliveryNode + @Root() { id: { id } }: NotificationDeliveryNode ): Promise { const notification = await this.notificationDeliveryRepository.findNotificationForDelivery({ - uuid, + uuid: id, }); if (notification == null) { diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 5b0cd84d..a8d18639 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -1,4 +1,5 @@ import { TeamType } from "@prisma/client"; +import type { GlobalId } from "@ukdanceblue/common"; import { AccessControl, AccessLevel, @@ -9,6 +10,7 @@ import { FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, + GlobalIdScalar, MembershipNode, MembershipPositionType, PersonNode, @@ -167,8 +169,10 @@ export class PersonResolver { @AccessControl({ accessLevel: AccessLevel.Committee }) @Query(() => GetPersonResponse, { name: "person" }) - async getByUuid(@Arg("uuid") uuid: string): Promise { - const row = await this.personRepository.findPersonByUnique({ uuid }); + async getByUuid( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.personRepository.findPersonByUnique({ uuid: id }); if (row == null) { return GetPersonResponse.newOk( @@ -272,7 +276,7 @@ export class PersonResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => GetPersonResponse, { name: "setPerson" }) async set( - @Arg("uuid") id: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetPersonInput ): Promise { const row = await this.personRepository.updatePerson( @@ -330,8 +334,10 @@ export class PersonResolver { @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @Mutation(() => DeletePersonResponse, { name: "deletePerson" }) - async delete(@Arg("uuid") uuid: string): Promise { - const result = await this.personRepository.deletePerson({ uuid }); + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const result = await this.personRepository.deletePerson({ uuid: id }); if (result == null) { throw new DetailedError(ErrorCode.DatabaseFailure, "Failed to delete"); @@ -361,11 +367,11 @@ export class PersonResolver { ) @FieldResolver(() => [CommitteeMembershipNode]) async committees( - @Root() person: PersonNode + @Root() { id: { id } }: PersonNode ): Promise { const models = await this.personRepository.findCommitteeMembershipsOfPerson( { - uuid: person.id, + uuid: id, } ); @@ -393,10 +399,10 @@ export class PersonResolver { } ) @FieldResolver(() => [MembershipNode]) - async teams(@Root() person: PersonNode): Promise { + async teams(@Root() { id: { id } }: PersonNode): Promise { const models = await this.personRepository.findMembershipsOfPerson( { - uuid: person.id, + uuid: id, }, {}, [TeamType.Spirit] @@ -421,10 +427,12 @@ export class PersonResolver { } ) @FieldResolver(() => [MembershipNode]) - async moraleTeams(@Root() person: PersonNode): Promise { + async moraleTeams( + @Root() { id: { id } }: PersonNode + ): Promise { const models = await this.personRepository.findMembershipsOfPerson( { - uuid: person.id, + uuid: id, }, {}, [TeamType.Morale] @@ -450,10 +458,10 @@ export class PersonResolver { ) @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) async primaryCommittee( - @Root() person: PersonNode + @Root() { id: { id } }: PersonNode ): Promise { const models = await this.personRepository.getPrimaryCommitteeOfPerson({ - uuid: person.id, + uuid: id, }); if (models == null) { @@ -473,7 +481,7 @@ export class PersonResolver { // 2. The captain of the team the entry is associated with { custom: async ( - { id }, + { id: { id } }, { teamMemberships, userData: { userId } } ): Promise => { if (userId == null) { @@ -510,7 +518,7 @@ export class PersonResolver { ) @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) async assignedDonationEntries( - @Root() person: PersonNode, + @Root() { id: { id } }: PersonNode, @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs ): Promise { const entries = await this.fundraisingEntryRepository.listEntries( @@ -529,7 +537,7 @@ export class PersonResolver { }, { // EXTREMELY IMPORTANT FOR SECURITY - assignedToPerson: { uuid: person.id }, + assignedToPerson: { uuid: id }, } ); const count = await this.fundraisingEntryRepository.countEntries({ @@ -566,11 +574,11 @@ export class PersonResolver { }) @FieldResolver(() => [FundraisingAssignmentNode]) async fundraisingAssignments( - @Root() person: PersonNode + @Root() { id: { id } }: PersonNode ): Promise { const models = await this.fundraisingEntryRepository.getAssignmentsForPerson({ - uuid: person.id, + uuid: id, }); if (models.isErr) { diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index b7a033fd..569ec760 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -1,7 +1,9 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, PersonNode, PointEntryNode, PointOpportunityNode, @@ -104,10 +106,10 @@ export class PointEntryResolver { @Query(() => GetPointEntryByUuidResponse, { name: "pointEntry" }) async getByUuid( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const model = await this.pointEntryRepository.findPointEntryByUnique({ - uuid, + uuid: id, }); if (model == null) { @@ -168,7 +170,9 @@ export class PointEntryResolver { } @Mutation(() => DeletePointEntryResponse, { name: "deletePointEntry" }) - async delete(@Arg("uuid") id: string): Promise { + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { await this.pointEntryRepository.deletePointEntry({ uuid: id }); return DeletePointEntryResponse.newOk(true); @@ -176,19 +180,19 @@ export class PointEntryResolver { @FieldResolver(() => PersonNode, { nullable: true }) async personFrom( - @Root() pointEntry: PointEntryNode + @Root() { id: { id } }: PointEntryNode ): Promise { const model = await this.pointEntryRepository.getPointEntryPersonFrom({ - uuid: pointEntry.id, + uuid: id, }); return model ? personModelToResource(model, this.personRepository) : null; } @FieldResolver(() => TeamNode) - async team(@Root() pointEntry: PointEntryNode): Promise { + async team(@Root() { id: { id } }: PointEntryNode): Promise { const model = await this.pointEntryRepository.getPointEntryTeam({ - uuid: pointEntry.id, + uuid: id, }); if (model == null) { @@ -200,10 +204,10 @@ export class PointEntryResolver { @FieldResolver(() => PointOpportunityNode, { nullable: true }) async pointOpportunity( - @Root() pointEntry: PointEntryNode + @Root() { id: { id } }: PointEntryNode ): Promise { const model = await this.pointEntryRepository.getPointEntryOpportunity({ - uuid: pointEntry.id, + uuid: id, }); return model ? pointOpportunityModelToResource(model) : null; diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index c3175591..7550c1e4 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -1,8 +1,10 @@ +import type { GlobalId } from "@ukdanceblue/common"; import { DetailedError, ErrorCode, EventNode, FilteredListQueryArgs, + GlobalIdScalar, PointOpportunityNode, SortDirection, TeamType, @@ -114,11 +116,11 @@ export class PointOpportunityResolver { @Query(() => SinglePointOpportunityResponse, { name: "pointOpportunity" }) async getByUuid( - @Arg("uuid") uuid: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const row = await this.pointOpportunityRepository.findPointOpportunityByUnique({ - uuid, + uuid: id, }); if (row == null) { @@ -183,11 +185,11 @@ export class PointOpportunityResolver { name: "setPointOpportunity", }) async set( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetPointOpportunityInput ): Promise { const row = await this.pointOpportunityRepository.updatePointOpportunity( - { uuid }, + { uuid: id }, { name: input.name ?? undefined, type: input.type ?? undefined, @@ -209,7 +211,7 @@ export class PointOpportunityResolver { name: "deletePointOpportunity", }) async delete( - @Arg("uuid") id: string + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId ): Promise { const row = await this.pointOpportunityRepository.deletePointOpportunity({ uuid: id, @@ -224,11 +226,11 @@ export class PointOpportunityResolver { @FieldResolver(() => EventNode, { nullable: true }) async event( - @Root() pointOpportunity: PointOpportunityNode + @Root() { id: { id } }: PointOpportunityNode ): Promise { const model = await this.pointOpportunityRepository.getEventForPointOpportunity({ - uuid: pointOpportunity.id, + uuid: id, }); return model ? eventModelToResource(model) : null; diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index a5b4630a..8f537ae4 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -1,4 +1,4 @@ -import type { OptionalToNullable } from "@ukdanceblue/common"; +import type { GlobalId, OptionalToNullable } from "@ukdanceblue/common"; import * as Common from "@ukdanceblue/common"; import { AccessControl, @@ -9,6 +9,7 @@ import { DetailedError, ErrorCode, FilteredListQueryArgs, + GlobalIdScalar, MembershipNode, PointEntryNode, SortDirection, @@ -156,8 +157,10 @@ export class TeamResolver { @AccessControl({ accessLevel: AccessLevel.Committee }) @Query(() => SingleTeamResponse, { name: "team" }) - async getByUuid(@Arg("uuid") uuid: string): Promise { - const row = await this.teamRepository.findTeamByUnique({ uuid }); + async getByUuid( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.teamRepository.findTeamByUnique({ uuid: id }); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Team not found"); @@ -263,13 +266,13 @@ export class TeamResolver { ) @Mutation(() => SingleTeamResponse, { name: "setTeam" }) async set( - @Arg("uuid") uuid: string, + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetTeamInput ): Promise { const row = await this.teamRepository.updateTeam( - { uuid }, + { uuid: id }, { - uuid, + uuid: id, name: input.name ?? undefined, type: input.type ?? undefined, legacyStatus: input.legacyStatus ?? undefined, @@ -299,8 +302,10 @@ export class TeamResolver { } ) @Mutation(() => DeleteTeamResponse, { name: "deleteTeam" }) - async delete(@Arg("uuid") uuid: string): Promise { - const row = await this.teamRepository.deleteTeam({ uuid }); + async delete( + @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.teamRepository.deleteTeam({ uuid: id }); if (row == null) { throw new DetailedError(ErrorCode.NotFound, "Team not found"); @@ -322,9 +327,9 @@ export class TeamResolver { } ) @FieldResolver(() => [MembershipNode]) - async members(@Root() team: TeamNode): Promise { + async members(@Root() { id: { id } }: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam({ - uuid: team.id, + uuid: id, }); return memberships.map((row) => membershipModelToResource(row)); @@ -334,9 +339,9 @@ export class TeamResolver { @FieldResolver(() => [MembershipNode], { deprecationReason: "Just query the members field and filter by role", }) - async captains(@Root() team: TeamNode): Promise { + async captains(@Root() { id: { id } }: TeamNode): Promise { const memberships = await this.teamRepository.findMembersOfTeam( - { uuid: team.id }, + { uuid: id }, { captainsOnly: true } ); @@ -356,9 +361,11 @@ export class TeamResolver { } ) @FieldResolver(() => [PointEntryNode]) - async pointEntries(@Root() team: TeamNode): Promise { + async pointEntries( + @Root() { id: { id } }: TeamNode + ): Promise { const rows = await this.teamRepository.getTeamPointEntries({ - uuid: team.id, + uuid: id, }); return rows.map((row) => pointEntryModelToResource(row)); @@ -366,9 +373,9 @@ export class TeamResolver { @AccessControl({ accessLevel: AccessLevel.Public }) @FieldResolver(() => Int) - async totalPoints(@Root() team: TeamNode): Promise { + async totalPoints(@Root() { id: { id } }: TeamNode): Promise { const result = await this.teamRepository.getTotalTeamPoints({ - uuid: team.id, + uuid: id, }); return result._sum.points ?? 0; @@ -376,8 +383,10 @@ export class TeamResolver { @AccessControl({ accessLevel: AccessLevel.Public }) @FieldResolver(() => Common.MarathonNode) - async marathon(@Root() team: TeamNode): Promise { - const result = await this.teamRepository.getMarathon({ uuid: team.id }); + async marathon( + @Root() { id: { id } }: TeamNode + ): Promise { + const result = await this.teamRepository.getMarathon({ uuid: id }); if (result == null) { throw new DetailedError(ErrorCode.NotFound, "Team not found"); @@ -402,7 +411,7 @@ export class TeamResolver { }) @FieldResolver(() => ListFundraisingEntriesResponse) async fundraisingEntries( - @Root() team: TeamNode, + @Root() { id: { id } }: TeamNode, @Args(() => ListFundraisingEntriesArgs) args: ListFundraisingEntriesArgs ): Promise { const entries = await this.fundraisingEntryRepository.listEntries( @@ -421,7 +430,7 @@ export class TeamResolver { }, { // EXTREMELY IMPORTANT FOR SECURITY - forTeam: { uuid: team.id }, + forTeam: { uuid: id }, } ); const count = await this.fundraisingEntryRepository.countEntries({ diff --git a/packages/server/src/routes/api/auth/login.ts b/packages/server/src/routes/api/auth/login.ts index 3f44dca6..d351cafc 100644 --- a/packages/server/src/routes/api/auth/login.ts +++ b/packages/server/src/routes/api/auth/login.ts @@ -2,7 +2,7 @@ import type { Context } from "koa"; import { generators } from "openid-client"; import { Container } from "typedi"; -import { LoginFlowSessionRepository } from "../../../resolvers/LoginFlowSession.js"; +import { LoginFlowSessionRepository } from "../../../repositories/LoginFlowSession.js"; import { makeOidcClient } from "./oidcClient.js"; diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index 549b289b..dc6558ea 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -8,9 +8,9 @@ import { DateTime } from "luxon"; import { Container } from "typedi"; import { makeUserJwt } from "../../../lib/auth/index.js"; +import { LoginFlowSessionRepository } from "../../../repositories/LoginFlowSession.js"; import { PersonRepository } from "../../../repositories/person/PersonRepository.js"; import { personModelToResource } from "../../../repositories/person/personModelToResource.js"; -import { LoginFlowSessionRepository } from "../../../resolvers/LoginFlowSession.js"; import { makeOidcClient } from "./oidcClient.js"; From 5c847436898c71ebcc2ccdfdb7bb4d37e94af13d Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 29 Jun 2024 04:58:36 +0000 Subject: [PATCH 127/153] Add NodeResolver --- packages/server/src/lib/error/error.ts | 13 ++ packages/server/src/lib/graphqlSchema.ts | 2 + .../configuration/ConfigurationRepository.ts | 4 + .../src/resolvers/ConfigurationResolver.ts | 17 +++ .../FundraisingAssignmentResolver.ts | 6 +- .../src/resolvers/FundraisingEntryResolver.ts | 10 +- packages/server/src/resolvers/NodeResolver.ts | 125 ++++++++++++++++++ .../server/src/resolvers/PersonResolver.ts | 11 +- 8 files changed, 175 insertions(+), 13 deletions(-) create mode 100644 packages/server/src/resolvers/NodeResolver.ts diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index b06fd7d1..ea461dbc 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -1,3 +1,6 @@ +import type { Result } from "true-myth"; +import { err, ok } from "true-myth/result"; + export abstract class ConcreteError { abstract get message(): string; get detailedMessage(): string { @@ -55,3 +58,13 @@ export type BasicError = JsError | UnknownError; export function toBasicError(error: unknown): BasicError { return error instanceof Error ? new JsError(error) : new UnknownError(error); } + +export async function flipPromise( + r: + | Result, Promise> + | Result> + | Result, E> + | Result +): Promise> { + return r.isOk ? ok(await r.value) : err(await r.error); +} diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index b816f2d3..6f23baa2 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -16,6 +16,7 @@ import { LoginStateResolver } from "../resolvers/LoginState.js"; import { MarathonHourResolver } from "../resolvers/MarathonHourResolver.js"; import { MarathonResolver } from "../resolvers/MarathonResolver.js"; import { MembershipResolver } from "../resolvers/MembershipResolver.js"; +import { NodeResolver } from "../resolvers/NodeResolver.js"; import { NotificationDeliveryResolver, NotificationResolver, @@ -79,6 +80,7 @@ const resolvers = [ FeedResolver, FundraisingAssignmentResolver, FundraisingEntryResolver, + NodeResolver, ] as const; for (const service of resolvers) { diff --git a/packages/server/src/repositories/configuration/ConfigurationRepository.ts b/packages/server/src/repositories/configuration/ConfigurationRepository.ts index da763c90..2889e240 100644 --- a/packages/server/src/repositories/configuration/ConfigurationRepository.ts +++ b/packages/server/src/repositories/configuration/ConfigurationRepository.ts @@ -4,6 +4,7 @@ import type { DateTime } from "luxon"; import { Service } from "typedi"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { SimpleUniqueParam } from "../shared.js"; import { buildConfigurationOrder, @@ -35,6 +36,9 @@ export class ConfigurationRepository { constructor(private prisma: PrismaClient) {} // Finders + findConfigurationByUnique(param: SimpleUniqueParam) { + return this.prisma.configuration.findUnique({ where: param }); + } findConfigurations( filters: readonly ConfigurationFilters[] | null | undefined, diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index 1ea6c39d..e49a0ab7 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -102,6 +102,23 @@ export class ConfigurationResolver { return GetConfigurationResponse.newOk(configurationModelToResource(row)); } + @Query(() => GetConfigurationResponse, { + name: "configuration", + }) + async getByUuid( + @Arg("id", () => GlobalIdScalar) { id }: GlobalId + ): Promise { + const row = await this.configurationRepository.findConfigurationByUnique({ + uuid: id, + }); + + if (row == null) { + throw new DetailedError(ErrorCode.NotFound, "Configuration not found"); + } + + return GetConfigurationResponse.newOk(configurationModelToResource(row)); + } + @Query(() => GetAllConfigurationsResponse, { name: "allConfigurations" }) async getAll(): Promise { const rows = await this.configurationRepository.findConfigurations(null, [ diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 0c90d356..e7b053d6 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -10,6 +10,7 @@ import { MembershipPositionType, PersonNode, } from "@ukdanceblue/common"; +import { map } from "true-myth/result"; import { Arg, Field, @@ -22,6 +23,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { flipPromise } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; @@ -64,13 +66,13 @@ export class FundraisingAssignmentResolver { @Query(() => FundraisingAssignmentNode) async fundraisingAssignment( @Arg("id", () => GlobalIdScalar) { id }: GlobalId - ): Promise>> { + ): Promise> { const assignment = await this.fundraisingEntryRepository.findAssignmentByUnique({ uuid: id, }); - return assignment.map(fundraisingAssignmentModelToNode); + return flipPromise(map(fundraisingAssignmentModelToNode, assignment)); } @AccessControl(fundraisingAccess) diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 6a696182..b19ed3c2 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -11,6 +11,7 @@ import { MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; +import { map } from "true-myth/result"; import { Arg, Args, @@ -24,6 +25,8 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { flipPromise } from "../lib/error/error.js"; +import { ConcreteResult } from "../lib/error/result.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; @@ -95,14 +98,11 @@ export class FundraisingEntryResolver { @Query(() => FundraisingEntryNode) async fundraisingEntry( @Arg("id", () => GlobalIdScalar) { id }: GlobalId - ): Promise { + ): Promise> { const entry = await this.fundraisingEntryRepository.findEntryByUnique({ uuid: id, }); - if (entry.isErr) { - throw new CatchableConcreteError(entry.error); - } - return fundraisingEntryModelToNode(entry.value); + return flipPromise(map(fundraisingEntryModelToNode, entry)); } @AccessControl(globalFundraisingAccessParam) diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts new file mode 100644 index 00000000..7ff837bb --- /dev/null +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -0,0 +1,125 @@ +import type { GlobalId } from "@ukdanceblue/common"; +import { + ConfigurationNode, + DeviceNode, + EventNode, + FundraisingAssignmentNode, + FundraisingEntryNode, + GlobalIdScalar, + ImageNode, + MarathonHourNode, + MarathonNode, + Node, + NotificationNode, + PersonNode, + PointEntryNode, + PointOpportunityNode, + TeamNode, +} from "@ukdanceblue/common"; +import { ok } from "true-myth/result"; +import { Arg, Query, Resolver } from "type-graphql"; +import { Service } from "typedi"; + +import { ConcreteResult } from "../lib/error/result.js"; + +import { ConfigurationResolver } from "./ConfigurationResolver.js"; +import { DeviceResolver } from "./DeviceResolver.js"; +import { EventResolver } from "./EventResolver.js"; +// import { FeedResolver } from "./FeedResolver.js"; +import { FundraisingAssignmentResolver } from "./FundraisingAssignmentResolver.js"; +import { FundraisingEntryResolver } from "./FundraisingEntryResolver.js"; +import { ImageResolver } from "./ImageResolver.js"; +import { MarathonHourResolver } from "./MarathonHourResolver.js"; +import { MarathonResolver } from "./MarathonResolver.js"; +import { NotificationResolver } from "./NotificationResolver.js"; +import { PersonResolver } from "./PersonResolver.js"; +import { PointEntryResolver } from "./PointEntryResolver.js"; +import { PointOpportunityResolver } from "./PointOpportunityResolver.js"; +import { TeamResolver } from "./TeamResolver.js"; + +@Resolver(() => Node) +@Service() +export class NodeResolver { + constructor( + private readonly configurationResolver: ConfigurationResolver, + private readonly deviceResolver: DeviceResolver, + private readonly eventResolver: EventResolver, + // private readonly feedResolver: FeedResolver, + private readonly fundraisingAssignmentResolver: FundraisingAssignmentResolver, + private readonly fundraisingEntryResolver: FundraisingEntryResolver, + private readonly imageResolver: ImageResolver, + private readonly marathonHourResolver: MarathonHourResolver, + private readonly marathonResolver: MarathonResolver, + private readonly notificationResolver: NotificationResolver, + private readonly personResolver: PersonResolver, + private readonly pointOpportunityResolver: PointOpportunityResolver, + private readonly pointEntryResolver: PointEntryResolver, + private readonly teamResolver: TeamResolver + ) {} + + @Query(() => Node) + async node( + @Arg("id", () => GlobalIdScalar) id: GlobalId + ): Promise> { + switch (id.typename) { + case ConfigurationNode.constructor.name: { + const { data } = await this.configurationResolver.getByUuid(id); + return ok(data); + } + case DeviceNode.constructor.name: { + const { data } = await this.deviceResolver.getByUuid(id); + return ok(data); + } + case EventNode.constructor.name: { + const { data } = await this.eventResolver.getByUuid(id); + return ok(data); + } + // TODO: fix this + // case FeedResolver.constructor.name: { + // const { data } = await this.feedResolver.getByUuid(id); + // return ok(data); + // } + case FundraisingAssignmentNode.constructor.name: { + return this.fundraisingAssignmentResolver.fundraisingAssignment(id); + } + case FundraisingEntryNode.constructor.name: { + return this.fundraisingEntryResolver.fundraisingEntry(id); + } + case ImageNode.constructor.name: { + const { data } = await this.imageResolver.getByUuid(id); + return ok(data); + } + case MarathonHourNode.constructor.name: { + const data = await this.marathonHourResolver.marathonHour(id); + return ok(data); + } + case MarathonNode.constructor.name: { + const data = await this.marathonResolver.marathon(id); + return ok(data); + } + case NotificationNode.constructor.name: { + const { data } = await this.notificationResolver.getByUuid(id); + return ok(data); + } + case PersonNode.constructor.name: { + const { data } = await this.personResolver.getByUuid(id); + return ok(data); + } + case PointOpportunityNode.constructor.name: { + const { data } = await this.pointOpportunityResolver.getByUuid(id); + return ok(data); + } + case PointEntryNode.constructor.name: { + const { data } = await this.pointEntryResolver.getByUuid(id); + return ok(data); + } + case TeamNode.constructor.name: { + const { data } = await this.teamResolver.getByUuid(id); + return ok(data); + } + default: { + throw new Error(`Unknown typename: ${id.typename}`); + } + } + } +} diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index a8d18639..6e8a63ad 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -33,6 +33,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { NotFoundError } from "../lib/error/direct.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; @@ -70,9 +71,9 @@ class CreatePersonResponse extends AbstractGraphQLCreatedResponse { @ObjectType("GetPersonResponse", { implements: AbstractGraphQLOkResponse, }) -class GetPersonResponse extends AbstractGraphQLOkResponse { +class GetPersonResponse extends AbstractGraphQLOkResponse { @Field(() => PersonNode, { nullable: true }) - data!: PersonNode | null; + data!: PersonNode; } @ObjectType("GetMembershipResponse", { implements: AbstractGraphQLOkResponse, @@ -175,12 +176,10 @@ export class PersonResolver { const row = await this.personRepository.findPersonByUnique({ uuid: id }); if (row == null) { - return GetPersonResponse.newOk( - null - ); + throw new CatchableConcreteError(new NotFoundError({ what: "Person" })); } - return GetPersonResponse.newOk( + return GetPersonResponse.newOk( await personModelToResource(row, this.personRepository) ); } From 491cbb48b691fd5f444e3f15d0ee2310137c56bd Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sat, 29 Jun 2024 05:02:39 +0000 Subject: [PATCH 128/153] Update schema --- schema.graphql | 130 +++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 59 deletions(-) diff --git a/schema.graphql b/schema.graphql index 8623a0bc..3765b6ff 100644 --- a/schema.graphql +++ b/schema.graphql @@ -78,7 +78,7 @@ enum CommitteeIdentifier { type CommitteeMembershipNode implements Node { createdAt: DateTimeISO - id: ID! + id: GlobalId! identifier: CommitteeIdentifier! person: PersonNode! position: MembershipPositionType! @@ -87,6 +87,13 @@ type CommitteeMembershipNode implements Node { updatedAt: DateTimeISO } +type CommitteeNode implements Node { + createdAt: DateTimeISO + id: GlobalId! + identifier: CommitteeIdentifier! + updatedAt: DateTimeISO +} + """Roles within a committee""" enum CommitteeRole { Chair @@ -96,7 +103,7 @@ enum CommitteeRole { type ConfigurationNode implements Node { createdAt: DateTimeISO - id: ID! + id: GlobalId! key: String! updatedAt: DateTimeISO validAfter: DateTimeISO @@ -221,7 +228,7 @@ scalar DateTimeISO type DbFundsTeamInfo implements Node { dbNum: Int! - id: ID! + id: GlobalId! name: String! } @@ -272,7 +279,7 @@ type DeleteTeamResponse implements AbstractGraphQLOkResponse & GraphQLBaseRespon type DeviceNode implements Node { createdAt: DateTimeISO - id: ID! + id: GlobalId! lastLoggedInUser: PersonNode lastLogin: DateTimeISO notificationDeliveries( @@ -366,7 +373,7 @@ scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/in type EventNode implements Node { createdAt: DateTimeISO description: String - id: ID! + id: GlobalId! images: [ImageNode!]! location: String occurrences: [EventOccurrenceNode!]! @@ -377,8 +384,8 @@ type EventNode implements Node { type EventOccurrenceNode { fullDay: Boolean! + id: ID! interval: IntervalISO! - uuid: ID! } enum EventResolverAllKeys { @@ -459,7 +466,7 @@ enum EventResolverStringFilterKeys { type FeedNode implements Node { createdAt: DateTimeISO - id: ID! + id: GlobalId! image: ImageNode textContent: String title: String! @@ -470,7 +477,7 @@ type FundraisingAssignmentNode implements Node { amount: Float! createdAt: DateTimeISO entry: FundraisingEntryNode! - id: ID! + id: GlobalId! """ The person assigned to this assignment, only null when access is denied @@ -486,7 +493,7 @@ type FundraisingEntryNode implements Node { donatedByText: String donatedOn: DateTimeISO! donatedToText: String - id: ID! + id: GlobalId! updatedAt: DateTimeISO } @@ -631,6 +638,9 @@ type GetPointEntryByUuidResponse implements AbstractGraphQLOkResponse & GraphQLB ok: Boolean! } +"""GlobalId custom scalar type""" +scalar GlobalId + """API response""" interface GraphQLBaseResponse { ok: Boolean! @@ -640,7 +650,7 @@ type ImageNode implements Node { alt: String createdAt: DateTimeISO height: Int! - id: ID! + id: GlobalId! mimeType: String! thumbHash: String updatedAt: DateTimeISO @@ -908,7 +918,7 @@ type MarathonHourNode implements Node { createdAt: DateTimeISO details: String durationInfo: String! - id: ID! + id: GlobalId! mapImages: [ImageNode!]! shownStartingAt: DateTimeISO! title: String! @@ -924,7 +934,7 @@ type MarathonNode implements Node { familyRelationsCommitteeTeam: TeamNode! fundraisingCommitteeTeam: TeamNode! hours: [MarathonHourNode!]! - id: ID! + id: GlobalId! marketingCommitteeTeam: TeamNode! miniMarathonsCommitteeTeam: TeamNode! operationsCommitteeTeam: TeamNode! @@ -978,7 +988,7 @@ input MarathonResolverKeyedIsNullFilterItem { type MembershipNode implements Node { createdAt: DateTimeISO - id: ID! + id: GlobalId! person: PersonNode! position: MembershipPositionType! team: TeamNode! @@ -992,10 +1002,10 @@ enum MembershipPositionType { } type Mutation { - abortScheduledNotification(uuid: String!): AbortScheduledNotificationResponse! - acknowledgeDeliveryIssue(uuid: String!): AcknowledgeDeliveryIssueResponse! + abortScheduledNotification(uuid: GlobalId!): AbortScheduledNotificationResponse! + acknowledgeDeliveryIssue(uuid: GlobalId!): AcknowledgeDeliveryIssueResponse! addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! - addMap(imageUuid: String!, uuid: String!): MarathonHourNode! + addMap(imageUuid: String!, uuid: GlobalId!): MarathonHourNode! addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! assignTeamToDbFundsTeam(dbFundsTeamId: Float!, teamId: String!): Void! @@ -1011,48 +1021,48 @@ type Mutation { createPointEntry(input: CreatePointEntryInput!): CreatePointEntryResponse! createPointOpportunity(input: CreatePointOpportunityInput!): CreatePointOpportunityResponse! createTeam(input: CreateTeamInput!, marathon: String!): CreateTeamResponse! - deleteConfiguration(uuid: String!): DeleteConfigurationResponse! - deleteDevice(uuid: String!): DeleteDeviceResponse! - deleteEvent(uuid: String!): DeleteEventResponse! + deleteConfiguration(uuid: GlobalId!): DeleteConfigurationResponse! + deleteDevice(uuid: GlobalId!): DeleteDeviceResponse! + deleteEvent(uuid: GlobalId!): DeleteEventResponse! deleteFeedItem(feedItemUuid: String!): Boolean! - deleteFundraisingAssignment(id: String!): FundraisingAssignmentNode! - deleteImage(uuid: String!): DeleteImageResponse! - deleteMarathon(uuid: String!): Void! - deleteMarathonHour(uuid: String!): Void! + deleteFundraisingAssignment(id: GlobalId!): FundraisingAssignmentNode! + deleteImage(uuid: GlobalId!): DeleteImageResponse! + deleteMarathon(uuid: GlobalId!): Void! + deleteMarathonHour(uuid: GlobalId!): Void! deleteNotification( """ If true, the notification will be deleted even if it has already been sent, which will also delete the delivery records. """ force: Boolean - uuid: String! + uuid: GlobalId! ): DeleteNotificationResponse! - deletePerson(uuid: String!): DeletePersonResponse! - deletePointEntry(uuid: String!): DeletePointEntryResponse! - deletePointOpportunity(uuid: String!): DeletePointOpportunityResponse! - deleteTeam(uuid: String!): DeleteTeamResponse! + deletePerson(uuid: GlobalId!): DeletePersonResponse! + deletePointEntry(uuid: GlobalId!): DeletePointEntryResponse! + deletePointOpportunity(uuid: GlobalId!): DeletePointOpportunityResponse! + deleteTeam(uuid: GlobalId!): DeleteTeamResponse! registerDevice(input: RegisterDeviceInput!): RegisterDeviceResponse! removeImageFromEvent(eventId: String!, imageId: String!): RemoveEventImageResponse! removeImageFromFeedItem(feedItemUuid: String!): FeedNode! - removeMap(imageUuid: String!, uuid: String!): Void! - scheduleNotification(sendAt: DateTimeISO!, uuid: String!): ScheduleNotificationResponse! + removeMap(imageUuid: String!, uuid: GlobalId!): Void! + scheduleNotification(sendAt: DateTimeISO!, uuid: GlobalId!): ScheduleNotificationResponse! """Send a notification immediately.""" - sendNotification(uuid: String!): SendNotificationResponse! - setEvent(input: SetEventInput!, uuid: String!): SetEventResponse! + sendNotification(uuid: GlobalId!): SendNotificationResponse! + setEvent(input: SetEventInput!, uuid: GlobalId!): SetEventResponse! setFeedItem(feedItemUuid: String!, input: SetFeedInput!): FeedNode! - setImageAltText(alt: String!, uuid: String!): ImageNode! - setImageUrl(uuid: String!): ImageNode! - setMarathon(input: SetMarathonInput!, uuid: String!): MarathonNode! - setMarathonHour(input: SetMarathonHourInput!, uuid: String!): MarathonHourNode! - setPerson(input: SetPersonInput!, uuid: String!): GetPersonResponse! - setPointOpportunity(input: SetPointOpportunityInput!, uuid: String!): SinglePointOpportunityResponse! - setTeam(input: SetTeamInput!, uuid: String!): SingleTeamResponse! + setImageAltText(alt: String!, uuid: GlobalId!): ImageNode! + setImageUrl(uuid: GlobalId!): ImageNode! + setMarathon(input: SetMarathonInput!, uuid: GlobalId!): MarathonNode! + setMarathonHour(input: SetMarathonHourInput!, uuid: GlobalId!): MarathonHourNode! + setPerson(input: SetPersonInput!, uuid: GlobalId!): GetPersonResponse! + setPointOpportunity(input: SetPointOpportunityInput!, uuid: GlobalId!): SinglePointOpportunityResponse! + setTeam(input: SetTeamInput!, uuid: GlobalId!): SingleTeamResponse! stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! - updateFundraisingAssignment(id: String!, input: UpdateFundraisingAssignmentInput!): FundraisingAssignmentNode! + updateFundraisingAssignment(id: GlobalId!, input: UpdateFundraisingAssignmentInput!): FundraisingAssignmentNode! } interface Node { - id: ID! + id: GlobalId! } """Integers that will have a value of 0 or more.""" @@ -1084,7 +1094,7 @@ type NotificationDeliveryNode implements Node { """Any error message returned by Expo when sending the notification.""" deliveryError: String - id: ID! + id: GlobalId! notification: NotificationNode! """The time the server received a delivery receipt from the user.""" @@ -1141,7 +1151,7 @@ type NotificationNode implements Node { deliveryIssue: String deliveryIssueAcknowledgedAt: DateTimeISO deliveryIssueCount: NotificationDeliveryIssueCount! - id: ID! + id: GlobalId! """ The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. @@ -1288,7 +1298,7 @@ type PersonNode implements Node { dbRole: DbRole! email: String! fundraisingAssignments: [FundraisingAssignmentNode!]! - id: ID! + id: GlobalId! linkblue: String moraleTeams: [MembershipNode!]! name: String @@ -1356,7 +1366,7 @@ enum PersonResolverStringFilterKeys { type PointEntryNode implements Node { comment: String createdAt: DateTimeISO - id: ID! + id: GlobalId! personFrom: PersonNode pointOpportunity: PointOpportunityNode points: Int! @@ -1401,7 +1411,7 @@ input PointEntryResolverKeyedIsNullFilterItem { type PointOpportunityNode implements Node { createdAt: DateTimeISO event: EventNode - id: ID! + id: GlobalId! name: String! opportunityDate: DateTimeISO type: TeamType! @@ -1485,10 +1495,11 @@ scalar PositiveInt type Query { activeConfiguration(key: String!): GetConfigurationByUuidResponse! allConfigurations: GetAllConfigurationsResponse! + configuration(id: GlobalId!): GetConfigurationByUuidResponse! currentMarathon: MarathonNode currentMarathonHour: MarathonHourNode dbFundsTeams(search: String!): [DbFundsTeamInfo!]! - device(uuid: String!): GetDeviceByUuidResponse! + device(uuid: GlobalId!): GetDeviceByUuidResponse! devices( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1532,7 +1543,7 @@ type Query { """The string filters to apply to the query""" stringFilters: [DeviceResolverKeyedStringFilterItem!] ): ListDevicesResponse! - event(uuid: String!): GetEventByUuidResponse! + event(uuid: GlobalId!): GetEventByUuidResponse! events( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1577,7 +1588,7 @@ type Query { stringFilters: [EventResolverKeyedStringFilterItem!] ): ListEventsResponse! feed(limit: Int = 10): [FeedNode!]! - fundraisingAssignment(id: String!): FundraisingAssignmentNode! + fundraisingAssignment(id: GlobalId!): FundraisingAssignmentNode! fundraisingEntries( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1621,8 +1632,8 @@ type Query { """The string filters to apply to the query""" stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! - fundraisingEntry(id: String!): FundraisingEntryNode! - image(uuid: String!): GetImageByUuidResponse! + fundraisingEntry(id: GlobalId!): FundraisingEntryNode! + image(uuid: GlobalId!): GetImageByUuidResponse! images( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1711,9 +1722,9 @@ type Query { stringFilters: [PersonResolverKeyedStringFilterItem!] ): ListPeopleResponse! loginState: LoginState! - marathon(uuid: String!): MarathonNode! + marathon(uuid: GlobalId!): MarathonNode! marathonForYear(year: String!): MarathonNode! - marathonHour(uuid: String!): MarathonHourNode! + marathonHour(uuid: GlobalId!): MarathonHourNode! marathons( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1758,7 +1769,8 @@ type Query { stringFilters: Void ): ListMarathonsResponse! me: GetPersonResponse! - notification(uuid: String!): GetNotificationByUuidResponse! + node(id: GlobalId!): Node! + notification(uuid: GlobalId!): GetNotificationByUuidResponse! notificationDeliveries( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1846,7 +1858,7 @@ type Query { """The string filters to apply to the query""" stringFilters: [NotificationResolverKeyedStringFilterItem!] ): ListNotificationsResponse! - person(uuid: String!): GetPersonResponse! + person(uuid: GlobalId!): GetPersonResponse! personByLinkBlue(linkBlueId: String!): GetPersonResponse! pointEntries( """The boolean filters to apply to the query""" @@ -1891,7 +1903,7 @@ type Query { """The string filters to apply to the query""" stringFilters: Void ): ListPointEntriesResponse! - pointEntry(uuid: String!): GetPointEntryByUuidResponse! + pointEntry(uuid: GlobalId!): GetPointEntryByUuidResponse! pointOpportunities( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1935,9 +1947,9 @@ type Query { """The string filters to apply to the query""" stringFilters: [PointOpportunityResolverKeyedStringFilterItem!] ): ListPointOpportunitiesResponse! - pointOpportunity(uuid: String!): SinglePointOpportunityResponse! + pointOpportunity(uuid: GlobalId!): SinglePointOpportunityResponse! searchPeopleByName(name: String!): GetPeopleResponse! - team(uuid: String!): SingleTeamResponse! + team(uuid: GlobalId!): SingleTeamResponse! teams( """The boolean filters to apply to the query""" booleanFilters: Void @@ -2165,7 +2177,7 @@ type TeamNode implements Node { """The string filters to apply to the query""" stringFilters: [FundraisingEntryResolverKeyedStringFilterItem!] ): ListFundraisingEntriesResponse! - id: ID! + id: GlobalId! legacyStatus: TeamLegacyStatus! marathon: MarathonNode! members: [MembershipNode!]! From b5c0e3797ba78722d8894502bb1eb9ff3398db8f Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 1 Jul 2024 16:22:14 +0000 Subject: [PATCH 129/153] Refactor code to use GlobalIdScalar for GraphQL API --- codegen.ts | 1 + .../common/lib/graphql-client-admin/gql.ts | 116 ++++---- .../lib/graphql-client-admin/graphql.ts | 258 ++++++++++-------- .../common/lib/graphql-client-public/gql.ts | 8 +- .../lib/graphql-client-public/graphql.ts | 150 +++++----- .../root/EventScreen/EventScreen.tsx | 4 +- .../root/EventScreen/EventScreenFragment.ts | 2 +- .../root/EventScreen/addToCalendar.ts | 4 +- .../root/NotificationScreen/refresh.ts | 2 +- .../EventListScreen/EventListRenderItem.tsx | 14 +- .../tab/EventListScreen/eventListUtils.ts | 2 +- packages/portal/src/config/marathon.tsx | 2 +- .../manage/NotificationManagerGQL.ts | 8 +- .../forms/person/edit/PersonEditorGQL.ts | 2 +- .../create/PointEntryCreatorGQL.ts | 2 +- .../elements/forms/team/edit/TeamEditorGQL.ts | 2 +- .../point-entry/PointEntryDeletePopup.tsx | 2 +- .../viewers/person/PersonDeletePopup.tsx | 2 +- .../elements/viewers/team/TeamDeletePopup.tsx | 2 +- .../pages/events/list-events/EventsTable.tsx | 4 +- .../single-event/edit-event/EditEventPage.tsx | 2 +- .../single-event/edit-event/EventEditorGQL.ts | 4 +- .../edit-event/useEventEditorForm.ts | 2 +- .../view-event/EventDeletePopup.tsx | 2 +- .../single-event/view-event/ViewEventPage.tsx | 2 +- .../single/edit/useMarathonEditorForm.ts | 7 +- .../marathon/single/view/ViewMarathonPage.tsx | 2 +- .../view/hour/edit/EditMarathonHourPage.tsx | 4 +- .../single/manage/ManageNotificationPage.tsx | 2 +- .../single/view/ViewNotificationPage.tsx | 2 +- .../edit-person/EditPersonPage.tsx | 2 +- .../view-person/ViewPersonPage.tsx | 2 +- .../single-team/edit-team/EditTeamPage.tsx | 2 +- .../fundraising/ViewTeamFundraising.tsx | 2 +- .../view-team/teamPageDocument.tsx | 2 +- 35 files changed, 337 insertions(+), 289 deletions(-) diff --git a/codegen.ts b/codegen.ts index 8ec74a6b..09e06cd1 100644 --- a/codegen.ts +++ b/codegen.ts @@ -49,6 +49,7 @@ const config: TypeScriptPluginConfig = { scalars: { LuxonDateRange: "string", LuxonDuration: "string", + GlobalId: "string", ...graphqlScalarsClientDefs, }, strictScalars: true, diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index a64b5677..6c72fe43 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -14,21 +14,21 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- */ const documents = { "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n marathons(sendAll: true) {\n data {\n id\n year\n }\n }\n }\n": types.ActiveMarathonDocument, - "\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n": types.SelectedMarathonDocument, + "\n query SelectedMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n": types.SelectedMarathonDocument, "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, "\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n": types.SingleNotificationFragmentFragmentDoc, "\n mutation CreateNotification(\n $title: String!\n $body: String!\n $audience: NotificationAudienceInput!\n $url: String\n ) {\n stageNotification(\n title: $title\n body: $body\n audience: $audience\n url: $url\n ) {\n uuid\n }\n }\n": types.CreateNotificationDocument, - "\n mutation CancelNotificationSchedule($uuid: String!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n": types.CancelNotificationScheduleDocument, - "\n mutation DeleteNotification($uuid: String!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n": types.DeleteNotificationDocument, - "\n mutation SendNotification($uuid: String!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n": types.SendNotificationDocument, - "\n mutation ScheduleNotification($uuid: String!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n": types.ScheduleNotificationDocument, + "\n mutation CancelNotificationSchedule($uuid: GlobalId!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n": types.CancelNotificationScheduleDocument, + "\n mutation DeleteNotification($uuid: GlobalId!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n": types.DeleteNotificationDocument, + "\n mutation SendNotification($uuid: GlobalId!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n": types.SendNotificationDocument, + "\n mutation ScheduleNotification($uuid: GlobalId!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n": types.ScheduleNotificationDocument, "\n fragment TeamNameFragment on TeamNode {\n id\n name\n }\n": types.TeamNameFragmentFragmentDoc, "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n ok\n uuid\n }\n }\n": types.PersonCreatorDocument, "\n fragment PersonEditorFragment on PersonNode {\n id\n name\n linkblue\n email\n teams {\n position\n team {\n id\n name\n }\n }\n }\n": types.PersonEditorFragmentFragmentDoc, - "\n mutation PersonEditor($uuid: String!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.PersonEditorDocument, + "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.PersonEditorDocument, "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n id\n }\n }\n }\n": types.CreatePointEntryDocument, - "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.GetPersonByUuidDocument, + "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.GetPersonByUuidDocument, "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n": types.GetPersonByLinkBlueDocument, "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n": types.SearchPersonByNameDocument, "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n uuid\n }\n }\n": types.CreatePersonByLinkBlueDocument, @@ -36,7 +36,7 @@ const documents = { "\n mutation CreatePointOpportunity($input: CreatePointOpportunityInput!) {\n createPointOpportunity(input: $input) {\n uuid\n }\n }\n": types.CreatePointOpportunityDocument, "\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n": types.TeamCreatorDocument, "\n fragment TeamEditorFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n type\n }\n": types.TeamEditorFragmentFragmentDoc, - "\n mutation TeamEditor($uuid: String!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.TeamEditorDocument, + "\n mutation TeamEditor($uuid: GlobalId!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.TeamEditorDocument, "\n fragment PeopleTableFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n primaryCommittee {\n identifier\n role\n }\n }\n": types.PeopleTableFragmentFragmentDoc, "\n query PeopleTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [PersonResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [PersonResolverKeyedOneOfFilterItem!]\n $stringFilters: [PersonResolverKeyedStringFilterItem!]\n ) {\n listPeople(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...PeopleTableFragment\n }\n }\n }\n": types.PeopleTableDocument, "\n query TeamsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $isNullFilters: [TeamResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [TeamResolverKeyedOneOfFilterItem!]\n $stringFilters: [TeamResolverKeyedStringFilterItem!]\n ) {\n teams(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...TeamsTableFragment\n }\n }\n }\n": types.TeamsTableDocument, @@ -45,25 +45,25 @@ const documents = { "\n query NotificationDeliveriesTableQuery(\n $notificationId: String!\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationDeliveryResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationDeliveryResolverKeyedIsNullFilterItem!]\n ) {\n notificationDeliveries(\n notificationUuid: $notificationId\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationDeliveriesTableFragment\n }\n }\n }\n": types.NotificationDeliveriesTableQueryDocument, "\n fragment NotificationsTableFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n }\n": types.NotificationsTableFragmentFragmentDoc, "\n query NotificationsTableQuery(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [NotificationResolverKeyedOneOfFilterItem!]\n $stringFilters: [NotificationResolverKeyedStringFilterItem!]\n ) {\n notifications(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationsTableFragment\n }\n }\n }\n": types.NotificationsTableQueryDocument, - "\n mutation DeletePointEntry($uuid: String!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePointEntryDocument, + "\n mutation DeletePointEntry($uuid: GlobalId!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePointEntryDocument, "\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n": types.PointEntryTableFragmentFragmentDoc, - "\n mutation DeletePerson($uuid: String!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePersonDocument, + "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePersonDocument, "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n": types.PersonViewerFragmentFragmentDoc, - "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, + "\n mutation DeleteTeam($uuid: GlobalId!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, "\n query LoginState {\n loginState {\n loggedIn\n dbRole\n effectiveCommitteeRoles {\n role\n identifier\n }\n }\n }\n": types.LoginStateDocument, "\n mutation CommitConfigChanges($changes: [CreateConfigurationInput!]!) {\n createConfigurations(input: $changes) {\n ok\n }\n }\n": types.CommitConfigChangesDocument, "\n fragment ConfigFragment on ConfigurationNode {\n id\n key\n value\n validAfter\n validUntil\n createdAt\n }\n": types.ConfigFragmentFragmentDoc, "\n query ConfigQuery {\n allConfigurations {\n data {\n ...ConfigFragment\n }\n }\n }\n ": types.ConfigQueryDocument, "\n mutation CreateEvent($input: CreateEventInput!) {\n createEvent(input: $input) {\n data {\n id\n }\n }\n }\n": types.CreateEventDocument, - "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n": types.EventsTableFragmentFragmentDoc, + "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n": types.EventsTableFragmentFragmentDoc, "\n query EventsTable(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [EventResolverKeyedDateFilterItem!]\n $isNullFilters: [EventResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [EventResolverKeyedOneOfFilterItem!]\n $stringFilters: [EventResolverKeyedStringFilterItem!]\n ) {\n events(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...EventsTableFragment\n }\n }\n }\n": types.EventsTableDocument, - "\n query EditEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.EditEventPageDocument, - "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n": types.EventEditorFragmentFragmentDoc, - "\n mutation SaveEvent($uuid: String!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.SaveEventDocument, - "\n mutation DeleteEvent($uuid: String!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteEventDocument, + "\n query EditEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.EditEventPageDocument, + "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n": types.EventEditorFragmentFragmentDoc, + "\n mutation SaveEvent($uuid: GlobalId!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n": types.SaveEventDocument, + "\n mutation DeleteEvent($uuid: GlobalId!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteEventDocument, "\n fragment EventViewerFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n createdAt\n updatedAt\n }\n": types.EventViewerFragmentFragmentDoc, - "\n query ViewEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n": types.ViewEventPageDocument, + "\n query ViewEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n": types.ViewEventPageDocument, "\n query FeedPage {\n feed(limit: null) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n }\n }\n }\n": types.FeedPageDocument, "\n mutation CreateFeedItem($input: CreateFeedInput!) {\n createFeedItem(input: $input) {\n id\n }\n }\n": types.CreateFeedItemDocument, "\n mutation DeleteFeedItem($uuid: String!) {\n deleteFeedItem(feedItemUuid: $uuid)\n }\n": types.DeleteFeedItemDocument, @@ -73,21 +73,21 @@ const documents = { "\n mutation CreateMarathon($input: CreateMarathonInput!) {\n createMarathon(input: $input) {\n id\n }\n }\n ": types.CreateMarathonDocument, "\n query MarathonOverviewPage {\n latestMarathon {\n ...MarathonViewerFragment\n }\n marathons(sendAll: true) {\n data {\n ...MarathonTableFragment\n }\n }\n }\n": types.MarathonOverviewPageDocument, "\n fragment MarathonTableFragment on MarathonNode {\n id\n year\n startDate\n endDate\n }\n": types.MarathonTableFragmentFragmentDoc, - "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n ": types.EditMarathonDocument, - "\n query GetMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n ": types.GetMarathonDocument, + "\n mutation EditMarathon(\n $input: SetMarathonInput!\n $marathonId: GlobalId!\n ) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n ": types.EditMarathonDocument, + "\n query GetMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n ": types.GetMarathonDocument, "\n fragment MarathonViewerFragment on MarathonNode {\n id\n year\n startDate\n endDate\n hours {\n id\n shownStartingAt\n title\n }\n }\n": types.MarathonViewerFragmentFragmentDoc, - "\n query MarathonPage($marathonUuid: String!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n": types.MarathonPageDocument, + "\n query MarathonPage($marathonUuid: GlobalId!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n": types.MarathonPageDocument, "\n mutation AddMarathonHour(\n $input: CreateMarathonHourInput!\n $marathonUuid: String!\n ) {\n createMarathonHour(input: $input, marathonUuid: $marathonUuid) {\n id\n }\n }\n ": types.AddMarathonHourDocument, - "\n query EditMarathonHourData($marathonHourUuid: String!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n": types.EditMarathonHourDataDocument, - "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n": types.EditMarathonHourDocument, - "\n query NotificationManager($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationManagerDocument, - "\n query NotificationViewer($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationViewerDocument, + "\n query EditMarathonHourData($marathonHourUuid: GlobalId!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n": types.EditMarathonHourDataDocument, + "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: GlobalId!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n": types.EditMarathonHourDocument, + "\n query NotificationManager($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationManagerDocument, + "\n query NotificationViewer($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationViewerDocument, "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.CreatePersonPageDocument, - "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, - "\n query ViewPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n": types.ViewPersonPageDocument, - "\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n": types.EditTeamPageDocument, - "\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n": types.ViewTeamFundraisingDocumentDocument, - "\n query ViewTeamPage($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n": types.ViewTeamPageDocument, + "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, + "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n": types.ViewPersonPageDocument, + "\n query EditTeamPage($uuid: GlobalId!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n": types.EditTeamPageDocument, + "\n query ViewTeamFundraisingDocument($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n": types.ViewTeamFundraisingDocumentDocument, + "\n query ViewTeamPage($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n": types.ViewTeamPageDocument, }; /** @@ -111,7 +111,7 @@ export function graphql(source: "\n query ActiveMarathon {\n latestMarathon /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query SelectedMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"]; +export function graphql(source: "\n query SelectedMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"): (typeof documents)["\n query SelectedMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -131,19 +131,19 @@ export function graphql(source: "\n mutation CreateNotification(\n $title: S /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CancelNotificationSchedule($uuid: String!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation CancelNotificationSchedule($uuid: String!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation CancelNotificationSchedule($uuid: GlobalId!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation CancelNotificationSchedule($uuid: GlobalId!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeleteNotification($uuid: String!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteNotification($uuid: String!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeleteNotification($uuid: GlobalId!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteNotification($uuid: GlobalId!, $force: Boolean) {\n deleteNotification(uuid: $uuid, force: $force) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation SendNotification($uuid: String!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation SendNotification($uuid: String!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation SendNotification($uuid: GlobalId!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation SendNotification($uuid: GlobalId!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation ScheduleNotification($uuid: String!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n"): (typeof documents)["\n mutation ScheduleNotification($uuid: String!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation ScheduleNotification($uuid: GlobalId!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n"): (typeof documents)["\n mutation ScheduleNotification($uuid: GlobalId!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -159,7 +159,7 @@ export function graphql(source: "\n fragment PersonEditorFragment on PersonNode /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation PersonEditor($uuid: String!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"): (typeof documents)["\n mutation PersonEditor($uuid: String!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"): (typeof documents)["\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -167,7 +167,7 @@ export function graphql(source: "\n mutation CreatePointEntry($input: CreatePoi /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: String!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -199,7 +199,7 @@ export function graphql(source: "\n fragment TeamEditorFragment on TeamNode {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation TeamEditor($uuid: String!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n"): (typeof documents)["\n mutation TeamEditor($uuid: String!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation TeamEditor($uuid: GlobalId!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n"): (typeof documents)["\n mutation TeamEditor($uuid: GlobalId!, $input: SetTeamInput!) {\n setTeam(uuid: $uuid, input: $input) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -235,7 +235,7 @@ export function graphql(source: "\n query NotificationsTableQuery(\n $page: /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeletePointEntry($uuid: String!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeletePointEntry($uuid: String!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeletePointEntry($uuid: GlobalId!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeletePointEntry($uuid: GlobalId!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -243,7 +243,7 @@ export function graphql(source: "\n fragment PointEntryTableFragment on PointEn /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeletePerson($uuid: String!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeletePerson($uuid: String!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -251,7 +251,7 @@ export function graphql(source: "\n fragment PersonViewerFragment on PersonNode /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteTeam($uuid: String!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeleteTeam($uuid: GlobalId!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteTeam($uuid: GlobalId!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -279,7 +279,7 @@ export function graphql(source: "\n mutation CreateEvent($input: CreateEventInp /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"): (typeof documents)["\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"]; +export function graphql(source: "\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"): (typeof documents)["\n fragment EventsTableFragment on EventNode {\n id\n title\n description\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n summary\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -287,19 +287,19 @@ export function graphql(source: "\n query EventsTable(\n $page: Int\n $pa /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"): (typeof documents)["\n query EditEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query EditEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"): (typeof documents)["\n query EditEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"): (typeof documents)["\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"]; +export function graphql(source: "\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"): (typeof documents)["\n fragment EventEditorFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n url\n width\n height\n thumbHash\n alt\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation SaveEvent($uuid: String!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"): (typeof documents)["\n mutation SaveEvent($uuid: String!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"]; +export function graphql(source: "\n mutation SaveEvent($uuid: GlobalId!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"): (typeof documents)["\n mutation SaveEvent($uuid: GlobalId!, $input: SetEventInput!) {\n setEvent(uuid: $uuid, input: $input) {\n data {\n ...EventEditorFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeleteEvent($uuid: String!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteEvent($uuid: String!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeleteEvent($uuid: GlobalId!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeleteEvent($uuid: GlobalId!) {\n deleteEvent(uuid: $uuid) {\n ok\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -307,7 +307,7 @@ export function graphql(source: "\n fragment EventViewerFragment on EventNode { /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ViewEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n"): (typeof documents)["\n query ViewEventPage($uuid: String!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ViewEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n"): (typeof documents)["\n query ViewEventPage($uuid: GlobalId!) {\n event(uuid: $uuid) {\n data {\n ...EventViewerFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -347,11 +347,11 @@ export function graphql(source: "\n fragment MarathonTableFragment on MarathonN /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "): (typeof documents)["\n mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "]; +export function graphql(source: "\n mutation EditMarathon(\n $input: SetMarathonInput!\n $marathonId: GlobalId!\n ) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "): (typeof documents)["\n mutation EditMarathon(\n $input: SetMarathonInput!\n $marathonId: GlobalId!\n ) {\n setMarathon(input: $input, uuid: $marathonId) {\n id\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n "): (typeof documents)["\n query GetMarathon($marathonId: String!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n "]; +export function graphql(source: "\n query GetMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n "): (typeof documents)["\n query GetMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n year\n startDate\n endDate\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -359,7 +359,7 @@ export function graphql(source: "\n fragment MarathonViewerFragment on Marathon /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query MarathonPage($marathonUuid: String!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n"): (typeof documents)["\n query MarathonPage($marathonUuid: String!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n"]; +export function graphql(source: "\n query MarathonPage($marathonUuid: GlobalId!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n"): (typeof documents)["\n query MarathonPage($marathonUuid: GlobalId!) {\n marathon(uuid: $marathonUuid) {\n ...MarathonViewerFragment\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -367,19 +367,19 @@ export function graphql(source: "\n mutation AddMarathonHour(\n $inp /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditMarathonHourData($marathonHourUuid: String!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n"): (typeof documents)["\n query EditMarathonHourData($marathonHourUuid: String!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n"]; +export function graphql(source: "\n query EditMarathonHourData($marathonHourUuid: GlobalId!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n"): (typeof documents)["\n query EditMarathonHourData($marathonHourUuid: GlobalId!) {\n marathonHour(uuid: $marathonHourUuid) {\n details\n durationInfo\n shownStartingAt\n title\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"): (typeof documents)["\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"]; +export function graphql(source: "\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: GlobalId!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"): (typeof documents)["\n mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: GlobalId!) {\n setMarathonHour(input: $input, uuid: $uuid) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query NotificationManager($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"): (typeof documents)["\n query NotificationManager($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query NotificationManager($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"): (typeof documents)["\n query NotificationManager($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query NotificationViewer($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"): (typeof documents)["\n query NotificationViewer($uuid: String!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query NotificationViewer($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"): (typeof documents)["\n query NotificationViewer($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -387,23 +387,23 @@ export function graphql(source: "\n query CreatePersonPage {\n teams(sendAll /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ViewPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"): (typeof documents)["\n query ViewPersonPage($uuid: String!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"): (typeof documents)["\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"): (typeof documents)["\n query EditTeamPage($uuid: String!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query EditTeamPage($uuid: GlobalId!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"): (typeof documents)["\n query EditTeamPage($uuid: GlobalId!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ViewTeamFundraisingDocument($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query ViewTeamFundraisingDocument($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ViewTeamFundraisingDocument($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ViewTeamPage($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n"): (typeof documents)["\n query ViewTeamPage($teamUuid: String!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query ViewTeamPage($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n"): (typeof documents)["\n query ViewTeamPage($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index 5f4b515e..e9ddf71d 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -26,6 +26,8 @@ export type Scalars = { DateTimeISO: { input: Date | string; output: Date | string; } /** A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. */ EmailAddress: { input: string; output: string; } + /** GlobalId custom scalar type */ + GlobalId: { input: string; output: string; } /** Integers that will have a value of 0 or more. */ NonNegativeInt: { input: number; output: number; } /** Integers that will have a value greater than 0. */ @@ -107,7 +109,7 @@ export type CommitteeIdentifier = typeof CommitteeIdentifier[keyof typeof Commit export type CommitteeMembershipNode = Node & { readonly __typename?: 'CommitteeMembershipNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly identifier: CommitteeIdentifier; readonly person: PersonNode; readonly position: MembershipPositionType; @@ -116,6 +118,14 @@ export type CommitteeMembershipNode = Node & { readonly updatedAt?: Maybe; }; +export type CommitteeNode = Node & { + readonly __typename?: 'CommitteeNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['GlobalId']['output']; + readonly identifier: CommitteeIdentifier; + readonly updatedAt?: Maybe; +}; + /** Roles within a committee */ export const CommitteeRole = { Chair: 'Chair', @@ -127,7 +137,7 @@ export type CommitteeRole = typeof CommitteeRole[keyof typeof CommitteeRole]; export type ConfigurationNode = Node & { readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly key: Scalars['String']['output']; readonly updatedAt?: Maybe; readonly validAfter?: Maybe; @@ -254,7 +264,7 @@ export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQ export type DbFundsTeamInfo = Node & { readonly __typename?: 'DbFundsTeamInfo'; readonly dbNum: Scalars['Int']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly name: Scalars['String']['output']; }; @@ -309,7 +319,7 @@ export type DeleteTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse export type DeviceNode = Node & { readonly __typename?: 'DeviceNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly lastLoggedInUser?: Maybe; readonly lastLogin?: Maybe; readonly notificationDeliveries: ReadonlyArray; @@ -388,7 +398,7 @@ export type EventNode = Node & { readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; readonly description?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly images: ReadonlyArray; readonly location?: Maybe; readonly occurrences: ReadonlyArray; @@ -400,8 +410,8 @@ export type EventNode = Node & { export type EventOccurrenceNode = { readonly __typename?: 'EventOccurrenceNode'; readonly fullDay: Scalars['Boolean']['output']; + readonly id: Scalars['ID']['output']; readonly interval: IntervalIso; - readonly uuid: Scalars['ID']['output']; }; export const EventResolverAllKeys = { @@ -472,7 +482,7 @@ export type EventResolverStringFilterKeys = typeof EventResolverStringFilterKeys export type FeedNode = Node & { readonly __typename?: 'FeedNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly image?: Maybe; readonly textContent?: Maybe; readonly title: Scalars['String']['output']; @@ -484,7 +494,7 @@ export type FundraisingAssignmentNode = Node & { readonly amount: Scalars['Float']['output']; readonly createdAt?: Maybe; readonly entry: FundraisingEntryNode; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; /** The person assigned to this assignment, only null when access is denied */ readonly person?: Maybe; readonly updatedAt?: Maybe; @@ -498,7 +508,7 @@ export type FundraisingEntryNode = Node & { readonly donatedByText?: Maybe; readonly donatedOn: Scalars['DateTimeISO']['output']; readonly donatedToText?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly updatedAt?: Maybe; }; @@ -650,7 +660,7 @@ export type ImageNode = Node & { readonly alt?: Maybe; readonly createdAt?: Maybe; readonly height: Scalars['Int']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly mimeType: Scalars['String']['output']; readonly thumbHash?: Maybe; readonly updatedAt?: Maybe; @@ -885,7 +895,7 @@ export type MarathonHourNode = Node & { readonly createdAt?: Maybe; readonly details?: Maybe; readonly durationInfo: Scalars['String']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly mapImages: ReadonlyArray; readonly shownStartingAt: Scalars['DateTimeISO']['output']; readonly title: Scalars['String']['output']; @@ -902,7 +912,7 @@ export type MarathonNode = Node & { readonly familyRelationsCommitteeTeam: TeamNode; readonly fundraisingCommitteeTeam: TeamNode; readonly hours: ReadonlyArray; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly marketingCommitteeTeam: TeamNode; readonly miniMarathonsCommitteeTeam: TeamNode; readonly operationsCommitteeTeam: TeamNode; @@ -952,7 +962,7 @@ export type MarathonResolverKeyedIsNullFilterItem = { export type MembershipNode = Node & { readonly __typename?: 'MembershipNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly person: PersonNode; readonly position: MembershipPositionType; readonly team: TeamNode; @@ -1017,12 +1027,12 @@ export type Mutation = { export type MutationAbortScheduledNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationAcknowledgeDeliveryIssueArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1034,7 +1044,7 @@ export type MutationAddExistingImageToEventArgs = { export type MutationAddMapArgs = { imageUuid: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1121,17 +1131,17 @@ export type MutationCreateTeamArgs = { export type MutationDeleteConfigurationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteDeviceArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteEventArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1141,48 +1151,48 @@ export type MutationDeleteFeedItemArgs = { export type MutationDeleteFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; export type MutationDeleteImageArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteMarathonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteMarathonHourArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteNotificationArgs = { force?: InputMaybe; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePersonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePointEntryArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePointOpportunityArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteTeamArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1204,24 +1214,24 @@ export type MutationRemoveImageFromFeedItemArgs = { export type MutationRemoveMapArgs = { imageUuid: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationScheduleNotificationArgs = { sendAt: Scalars['DateTimeISO']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSendNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetEventArgs = { input: SetEventInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1233,42 +1243,42 @@ export type MutationSetFeedItemArgs = { export type MutationSetImageAltTextArgs = { alt: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetImageUrlArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetMarathonArgs = { input: SetMarathonInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetMarathonHourArgs = { input: SetMarathonHourInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetPersonArgs = { input: SetPersonInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetPointOpportunityArgs = { input: SetPointOpportunityInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetTeamArgs = { input: SetTeamInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1281,12 +1291,12 @@ export type MutationStageNotificationArgs = { export type MutationUpdateFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; input: UpdateFundraisingAssignmentInput; }; export type Node = { - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; }; export type NotificationAudienceInput = { @@ -1314,7 +1324,7 @@ export type NotificationDeliveryNode = Node & { readonly createdAt?: Maybe; /** Any error message returned by Expo when sending the notification. */ readonly deliveryError?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly notification: NotificationNode; /** The time the server received a delivery receipt from the user. */ readonly receiptCheckedAt?: Maybe; @@ -1365,7 +1375,7 @@ export type NotificationNode = Node & { readonly deliveryIssue?: Maybe; readonly deliveryIssueAcknowledgedAt?: Maybe; readonly deliveryIssueCount: NotificationDeliveryIssueCount; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ readonly sendAt?: Maybe; /** The time the server started sending the notification. */ @@ -1450,7 +1460,7 @@ export type PersonNode = Node & { readonly dbRole: DbRole; readonly email: Scalars['String']['output']; readonly fundraisingAssignments: ReadonlyArray; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly linkblue?: Maybe; readonly moraleTeams: ReadonlyArray; readonly name?: Maybe; @@ -1528,7 +1538,7 @@ export type PointEntryNode = Node & { readonly __typename?: 'PointEntryNode'; readonly comment?: Maybe; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly personFrom?: Maybe; readonly pointOpportunity?: Maybe; readonly points: Scalars['Int']['output']; @@ -1569,7 +1579,7 @@ export type PointOpportunityNode = Node & { readonly __typename?: 'PointOpportunityNode'; readonly createdAt?: Maybe; readonly event?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly name: Scalars['String']['output']; readonly opportunityDate?: Maybe; readonly type: TeamType; @@ -1641,6 +1651,7 @@ export type Query = { readonly __typename?: 'Query'; readonly activeConfiguration: GetConfigurationByUuidResponse; readonly allConfigurations: GetAllConfigurationsResponse; + readonly configuration: GetConfigurationByUuidResponse; readonly currentMarathon?: Maybe; readonly currentMarathonHour?: Maybe; readonly dbFundsTeams: ReadonlyArray; @@ -1662,6 +1673,7 @@ export type Query = { readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; + readonly node: Node; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -1682,13 +1694,18 @@ export type QueryActiveConfigurationArgs = { }; +export type QueryConfigurationArgs = { + id: Scalars['GlobalId']['input']; +}; + + export type QueryDbFundsTeamsArgs = { search: Scalars['String']['input']; }; export type QueryDeviceArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1709,7 +1726,7 @@ export type QueryDevicesArgs = { export type QueryEventArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1735,7 +1752,7 @@ export type QueryFeedArgs = { export type QueryFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; @@ -1756,12 +1773,12 @@ export type QueryFundraisingEntriesArgs = { export type QueryFundraisingEntryArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; export type QueryImageArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1798,7 +1815,7 @@ export type QueryListPeopleArgs = { export type QueryMarathonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1808,7 +1825,7 @@ export type QueryMarathonForYearArgs = { export type QueryMarathonHourArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1828,8 +1845,13 @@ export type QueryMarathonsArgs = { }; +export type QueryNodeArgs = { + id: Scalars['GlobalId']['input']; +}; + + export type QueryNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1867,7 +1889,7 @@ export type QueryNotificationsArgs = { export type QueryPersonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1893,7 +1915,7 @@ export type QueryPointEntriesArgs = { export type QueryPointEntryArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1914,7 +1936,7 @@ export type QueryPointOpportunitiesArgs = { export type QueryPointOpportunityArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1924,7 +1946,7 @@ export type QuerySearchPeopleByNameArgs = { export type QueryTeamArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -2073,7 +2095,7 @@ export type TeamNode = Node & { readonly captains: ReadonlyArray; readonly createdAt?: Maybe; readonly fundraisingEntries: ListFundraisingEntriesResponse; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly legacyStatus: TeamLegacyStatus; readonly marathon: MarathonNode; readonly members: ReadonlyArray; @@ -2157,7 +2179,7 @@ export type ActiveMarathonQueryVariables = Exact<{ [key: string]: never; }>; export type ActiveMarathonQuery = { readonly __typename?: 'Query', readonly latestMarathon?: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null } | null, readonly marathons: { readonly __typename?: 'ListMarathonsResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string }> } }; export type SelectedMarathonQueryVariables = Exact<{ - marathonId: Scalars['String']['input']; + marathonId: Scalars['GlobalId']['input']; }>; @@ -2190,14 +2212,14 @@ export type CreateNotificationMutationVariables = Exact<{ export type CreateNotificationMutation = { readonly __typename?: 'Mutation', readonly stageNotification: { readonly __typename?: 'StageNotificationResponse', readonly uuid: string } }; export type CancelNotificationScheduleMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; export type CancelNotificationScheduleMutation = { readonly __typename?: 'Mutation', readonly abortScheduledNotification: { readonly __typename?: 'AbortScheduledNotificationResponse', readonly ok: boolean } }; export type DeleteNotificationMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; force?: InputMaybe; }>; @@ -2205,14 +2227,14 @@ export type DeleteNotificationMutationVariables = Exact<{ export type DeleteNotificationMutation = { readonly __typename?: 'Mutation', readonly deleteNotification: { readonly __typename?: 'DeleteNotificationResponse', readonly ok: boolean } }; export type SendNotificationMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; export type SendNotificationMutation = { readonly __typename?: 'Mutation', readonly sendNotification: { readonly __typename?: 'SendNotificationResponse', readonly ok: boolean } }; export type ScheduleNotificationMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; sendAt: Scalars['DateTimeISO']['input']; }>; @@ -2231,7 +2253,7 @@ export type PersonCreatorMutation = { readonly __typename?: 'Mutation', readonly export type PersonEditorFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonEditorFragmentFragment' }; export type PersonEditorMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; input: SetPersonInput; }>; @@ -2246,7 +2268,7 @@ export type CreatePointEntryMutationVariables = Exact<{ export type CreatePointEntryMutation = { readonly __typename?: 'Mutation', readonly createPointEntry: { readonly __typename?: 'CreatePointEntryResponse', readonly data: { readonly __typename?: 'PointEntryNode', readonly id: string } } }; export type GetPersonByUuidQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2300,7 +2322,7 @@ export type TeamCreatorMutation = { readonly __typename?: 'Mutation', readonly c export type TeamEditorFragmentFragment = { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string, readonly legacyStatus: TeamLegacyStatus, readonly type: TeamType, readonly marathon: { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string } } & { ' $fragmentName'?: 'TeamEditorFragmentFragment' }; export type TeamEditorMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; input: SetTeamInput; }>; @@ -2381,7 +2403,7 @@ export type NotificationsTableQueryQuery = { readonly __typename?: 'Query', read )> } }; export type DeletePointEntryMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2390,7 +2412,7 @@ export type DeletePointEntryMutation = { readonly __typename?: 'Mutation', reado export type PointEntryTableFragmentFragment = { readonly __typename?: 'PointEntryNode', readonly id: string, readonly points: number, readonly comment?: string | null, readonly personFrom?: { readonly __typename?: 'PersonNode', readonly name?: string | null, readonly linkblue?: string | null } | null, readonly pointOpportunity?: { readonly __typename?: 'PointOpportunityNode', readonly name: string, readonly opportunityDate?: Date | string | null } | null } & { ' $fragmentName'?: 'PointEntryTableFragmentFragment' }; export type DeletePersonMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2399,7 +2421,7 @@ export type DeletePersonMutation = { readonly __typename?: 'Mutation', readonly export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }>, readonly committees: ReadonlyArray<{ readonly __typename?: 'CommitteeMembershipNode', readonly identifier: CommitteeIdentifier, readonly role: CommitteeRole }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; export type DeleteTeamMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2436,7 +2458,7 @@ export type CreateEventMutationVariables = Exact<{ export type CreateEventMutation = { readonly __typename?: 'Mutation', readonly createEvent: { readonly __typename?: 'CreateEventResponse', readonly data: { readonly __typename?: 'EventNode', readonly id: string } } }; -export type EventsTableFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly description?: string | null, readonly summary?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }> } & { ' $fragmentName'?: 'EventsTableFragmentFragment' }; +export type EventsTableFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly description?: string | null, readonly summary?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly id: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }> } & { ' $fragmentName'?: 'EventsTableFragmentFragment' }; export type EventsTableQueryVariables = Exact<{ page?: InputMaybe; @@ -2456,7 +2478,7 @@ export type EventsTableQuery = { readonly __typename?: 'Query', readonly events: )> } }; export type EditEventPageQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2465,10 +2487,10 @@ export type EditEventPageQuery = { readonly __typename?: 'Query', readonly event & { ' $fragmentRefs'?: { 'EventEditorFragmentFragment': EventEditorFragmentFragment } } ) } }; -export type EventEditorFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventEditorFragmentFragment' }; +export type EventEditorFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly id: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventEditorFragmentFragment' }; export type SaveEventMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; input: SetEventInput; }>; @@ -2479,7 +2501,7 @@ export type SaveEventMutation = { readonly __typename?: 'Mutation', readonly set ) } }; export type DeleteEventMutationVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2488,7 +2510,7 @@ export type DeleteEventMutation = { readonly __typename?: 'Mutation', readonly d export type EventViewerFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly createdAt?: Date | string | null, readonly updatedAt?: Date | string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly url?: URL | string | null, readonly width: number, readonly height: number, readonly thumbHash?: string | null, readonly alt?: string | null }> } & { ' $fragmentName'?: 'EventViewerFragmentFragment' }; export type ViewEventPageQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2565,14 +2587,14 @@ export type MarathonTableFragmentFragment = { readonly __typename?: 'MarathonNod export type EditMarathonMutationVariables = Exact<{ input: SetMarathonInput; - marathonId: Scalars['String']['input']; + marathonId: Scalars['GlobalId']['input']; }>; export type EditMarathonMutation = { readonly __typename?: 'Mutation', readonly setMarathon: { readonly __typename?: 'MarathonNode', readonly id: string } }; export type GetMarathonQueryVariables = Exact<{ - marathonId: Scalars['String']['input']; + marathonId: Scalars['GlobalId']['input']; }>; @@ -2581,7 +2603,7 @@ export type GetMarathonQuery = { readonly __typename?: 'Query', readonly maratho export type MarathonViewerFragmentFragment = { readonly __typename?: 'MarathonNode', readonly id: string, readonly year: string, readonly startDate?: Date | string | null, readonly endDate?: Date | string | null, readonly hours: ReadonlyArray<{ readonly __typename?: 'MarathonHourNode', readonly id: string, readonly shownStartingAt: Date | string, readonly title: string }> } & { ' $fragmentName'?: 'MarathonViewerFragmentFragment' }; export type MarathonPageQueryVariables = Exact<{ - marathonUuid: Scalars['String']['input']; + marathonUuid: Scalars['GlobalId']['input']; }>; @@ -2599,7 +2621,7 @@ export type AddMarathonHourMutationVariables = Exact<{ export type AddMarathonHourMutation = { readonly __typename?: 'Mutation', readonly createMarathonHour: { readonly __typename?: 'MarathonHourNode', readonly id: string } }; export type EditMarathonHourDataQueryVariables = Exact<{ - marathonHourUuid: Scalars['String']['input']; + marathonHourUuid: Scalars['GlobalId']['input']; }>; @@ -2607,14 +2629,14 @@ export type EditMarathonHourDataQuery = { readonly __typename?: 'Query', readonl export type EditMarathonHourMutationVariables = Exact<{ input: SetMarathonHourInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; export type EditMarathonHourMutation = { readonly __typename?: 'Mutation', readonly setMarathonHour: { readonly __typename?: 'MarathonHourNode', readonly id: string } }; export type NotificationManagerQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2624,7 +2646,7 @@ export type NotificationManagerQuery = { readonly __typename?: 'Query', readonly ) } }; export type NotificationViewerQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2642,7 +2664,7 @@ export type CreatePersonPageQuery = { readonly __typename?: 'Query', readonly te )> } }; export type EditPersonPageQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2655,7 +2677,7 @@ export type EditPersonPageQuery = { readonly __typename?: 'Query', readonly pers )> } }; export type ViewPersonPageQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2665,7 +2687,7 @@ export type ViewPersonPageQuery = { readonly __typename?: 'Query', readonly pers ) | null } }; export type EditTeamPageQueryVariables = Exact<{ - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }>; @@ -2675,14 +2697,14 @@ export type EditTeamPageQuery = { readonly __typename?: 'Query', readonly team: ) } }; export type ViewTeamFundraisingDocumentQueryVariables = Exact<{ - teamUuid: Scalars['String']['input']; + teamUuid: Scalars['GlobalId']['input']; }>; export type ViewTeamFundraisingDocumentQuery = { readonly __typename?: 'Query', readonly team: { readonly __typename?: 'SingleTeamResponse', readonly data: { readonly __typename?: 'TeamNode', readonly fundraisingEntries: { readonly __typename?: 'ListFundraisingEntriesResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'FundraisingEntryNode', readonly id: string, readonly amount: number, readonly donatedByText?: string | null, readonly donatedToText?: string | null, readonly donatedOn: Date | string, readonly assignments: ReadonlyArray<{ readonly __typename?: 'FundraisingAssignmentNode', readonly id: string, readonly amount: number, readonly person?: { readonly __typename?: 'PersonNode', readonly name?: string | null } | null }> }> } } } }; export type ViewTeamPageQueryVariables = Exact<{ - teamUuid: Scalars['String']['input']; + teamUuid: Scalars['GlobalId']['input']; }>; @@ -2706,48 +2728,48 @@ export const PointEntryTableFragmentFragmentDoc = {"kind":"Document","definition export const PersonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TeamViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}}]} as unknown as DocumentNode; export const ConfigFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const EventsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; -export const EventEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const EventsTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; +export const EventEditorFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; export const EventViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const ImagesTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const MarathonTableFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; export const ActiveMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}}]}}]}}]} as unknown as DocumentNode; -export const SelectedMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectedMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; +export const SelectedMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectedMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"title"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"body"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"audience"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationAudienceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"url"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stageNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"title"},"value":{"kind":"Variable","name":{"kind":"Name","value":"title"}}},{"kind":"Argument","name":{"kind":"Name","value":"body"},"value":{"kind":"Variable","name":{"kind":"Name","value":"body"}}},{"kind":"Argument","name":{"kind":"Name","value":"audience"},"value":{"kind":"Variable","name":{"kind":"Name","value":"audience"}}},{"kind":"Argument","name":{"kind":"Name","value":"url"},"value":{"kind":"Variable","name":{"kind":"Name","value":"url"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const CancelNotificationScheduleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelNotificationSchedule"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"abortScheduledNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeleteNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"force"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"force"},"value":{"kind":"Variable","name":{"kind":"Name","value":"force"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const SendNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sendNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const ScheduleNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ScheduleNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduleNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"sendAt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const CancelNotificationScheduleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelNotificationSchedule"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"abortScheduledNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const DeleteNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"force"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"force"},"value":{"kind":"Variable","name":{"kind":"Name","value":"force"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const SendNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sendNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const ScheduleNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ScheduleNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduleNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"sendAt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const PersonCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const PersonEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetPersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const PersonEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetPersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const CreatePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetPersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const SearchPersonByNameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPersonByName"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreatePersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EmailAddress"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"linkblue"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"memberOf"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const PointEntryOpportunityLookupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PointEntryOpportunityLookup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pointOpportunities"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"name"}},{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"SUBSTRING"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreatePointOpportunityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointOpportunity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointOpportunityInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointOpportunity"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathon"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const TeamEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const TeamEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetTeamInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const PeopleTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeopleTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PersonResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"listPeople"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PeopleTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PeopleTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TeamsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; -export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"effectiveCommitteeRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identifier"}}]}}]}}]}}]} as unknown as DocumentNode; export const CommitConfigChangesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitConfigChanges"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"changes"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateConfigurationInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createConfigurations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"changes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const ConfigQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ConfigQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allConfigurations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ConfigFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ConfigFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const CreateEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const EventsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EventsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; -export const EditEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; -export const SaveEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SaveEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; -export const DeleteEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const ViewEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; +export const EventsTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EventsTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EventResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"summary"}}]}}]} as unknown as DocumentNode; +export const EditEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const SaveEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SaveEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetEventInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]} as unknown as DocumentNode; +export const DeleteEventDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteEvent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteEvent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const ViewEventPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewEventPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const FeedPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FeedPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateFeedItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateFeedItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateFeedInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createFeedItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const DeleteFeedItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteFeedItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteFeedItem"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"feedItemUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}]}]}}]} as unknown as DocumentNode; @@ -2755,17 +2777,17 @@ export const CreateImageDocument = {"kind":"Document","definitions":[{"kind":"Op export const ImagesTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagesTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedNumericFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"numericFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"numericFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImagesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImagesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; export const CreateMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const MarathonOverviewPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonOverviewPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]} as unknown as DocumentNode; -export const EditMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const GetMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; -export const MarathonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; +export const EditMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const GetMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; +export const MarathonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MarathonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MarathonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; export const AddMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathonUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const EditMarathonHourDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditMarathonHourData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; -export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; -export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; +export const EditMarathonHourDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditMarathonHourData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonHourUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"shownStartingAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode; +export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EditMarathonHour"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetMarathonHourInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setMarathonHour"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; +export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; -export const ViewTeamFundraisingDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamFundraisingDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fundraisingEntries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"donatedByText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedToText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; +export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ViewTeamFundraisingDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamFundraisingDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fundraisingEntries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"donatedByText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedToText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index f46cb151..6c56926b 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -24,8 +24,8 @@ const documents = { "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n ": types.TriviaCrackDocument, "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, "\n mutation SetDevice($input: RegisterDeviceInput!) {\n registerDevice(input: $input) {\n ok\n }\n }\n": types.SetDeviceDocument, - "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, - "\n query DeviceNotifications(\n $deviceUuid: String!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n": types.DeviceNotificationsDocument, + "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, + "\n query DeviceNotifications(\n $deviceUuid: GlobalId!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n": types.DeviceNotificationsDocument, "\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n": types.ProfileScreenAuthFragmentFragmentDoc, "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n": types.RootScreenDocumentDocument, @@ -102,11 +102,11 @@ export function graphql(source: "\n mutation SetDevice($input: RegisterDeviceIn /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"): (typeof documents)["\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n uuid\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"]; +export function graphql(source: "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"): (typeof documents)["\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query DeviceNotifications(\n $deviceUuid: String!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n"): (typeof documents)["\n query DeviceNotifications(\n $deviceUuid: String!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query DeviceNotifications(\n $deviceUuid: GlobalId!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n"): (typeof documents)["\n query DeviceNotifications(\n $deviceUuid: GlobalId!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index cd435811..b522eabc 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -26,6 +26,8 @@ export type Scalars = { DateTimeISO: { input: Date | string; output: Date | string; } /** A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. */ EmailAddress: { input: string; output: string; } + /** GlobalId custom scalar type */ + GlobalId: { input: string; output: string; } /** Integers that will have a value of 0 or more. */ NonNegativeInt: { input: number; output: number; } /** Integers that will have a value greater than 0. */ @@ -107,7 +109,7 @@ export type CommitteeIdentifier = typeof CommitteeIdentifier[keyof typeof Commit export type CommitteeMembershipNode = Node & { readonly __typename?: 'CommitteeMembershipNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly identifier: CommitteeIdentifier; readonly person: PersonNode; readonly position: MembershipPositionType; @@ -116,6 +118,14 @@ export type CommitteeMembershipNode = Node & { readonly updatedAt?: Maybe; }; +export type CommitteeNode = Node & { + readonly __typename?: 'CommitteeNode'; + readonly createdAt?: Maybe; + readonly id: Scalars['GlobalId']['output']; + readonly identifier: CommitteeIdentifier; + readonly updatedAt?: Maybe; +}; + /** Roles within a committee */ export const CommitteeRole = { Chair: 'Chair', @@ -127,7 +137,7 @@ export type CommitteeRole = typeof CommitteeRole[keyof typeof CommitteeRole]; export type ConfigurationNode = Node & { readonly __typename?: 'ConfigurationNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly key: Scalars['String']['output']; readonly updatedAt?: Maybe; readonly validAfter?: Maybe; @@ -254,7 +264,7 @@ export type CreateTeamResponse = AbstractGraphQlCreatedResponse & AbstractGraphQ export type DbFundsTeamInfo = Node & { readonly __typename?: 'DbFundsTeamInfo'; readonly dbNum: Scalars['Int']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly name: Scalars['String']['output']; }; @@ -309,7 +319,7 @@ export type DeleteTeamResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse export type DeviceNode = Node & { readonly __typename?: 'DeviceNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly lastLoggedInUser?: Maybe; readonly lastLogin?: Maybe; readonly notificationDeliveries: ReadonlyArray; @@ -388,7 +398,7 @@ export type EventNode = Node & { readonly __typename?: 'EventNode'; readonly createdAt?: Maybe; readonly description?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly images: ReadonlyArray; readonly location?: Maybe; readonly occurrences: ReadonlyArray; @@ -400,8 +410,8 @@ export type EventNode = Node & { export type EventOccurrenceNode = { readonly __typename?: 'EventOccurrenceNode'; readonly fullDay: Scalars['Boolean']['output']; + readonly id: Scalars['ID']['output']; readonly interval: IntervalIso; - readonly uuid: Scalars['ID']['output']; }; export const EventResolverAllKeys = { @@ -472,7 +482,7 @@ export type EventResolverStringFilterKeys = typeof EventResolverStringFilterKeys export type FeedNode = Node & { readonly __typename?: 'FeedNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly image?: Maybe; readonly textContent?: Maybe; readonly title: Scalars['String']['output']; @@ -484,7 +494,7 @@ export type FundraisingAssignmentNode = Node & { readonly amount: Scalars['Float']['output']; readonly createdAt?: Maybe; readonly entry: FundraisingEntryNode; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; /** The person assigned to this assignment, only null when access is denied */ readonly person?: Maybe; readonly updatedAt?: Maybe; @@ -498,7 +508,7 @@ export type FundraisingEntryNode = Node & { readonly donatedByText?: Maybe; readonly donatedOn: Scalars['DateTimeISO']['output']; readonly donatedToText?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly updatedAt?: Maybe; }; @@ -650,7 +660,7 @@ export type ImageNode = Node & { readonly alt?: Maybe; readonly createdAt?: Maybe; readonly height: Scalars['Int']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly mimeType: Scalars['String']['output']; readonly thumbHash?: Maybe; readonly updatedAt?: Maybe; @@ -885,7 +895,7 @@ export type MarathonHourNode = Node & { readonly createdAt?: Maybe; readonly details?: Maybe; readonly durationInfo: Scalars['String']['output']; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly mapImages: ReadonlyArray; readonly shownStartingAt: Scalars['DateTimeISO']['output']; readonly title: Scalars['String']['output']; @@ -902,7 +912,7 @@ export type MarathonNode = Node & { readonly familyRelationsCommitteeTeam: TeamNode; readonly fundraisingCommitteeTeam: TeamNode; readonly hours: ReadonlyArray; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly marketingCommitteeTeam: TeamNode; readonly miniMarathonsCommitteeTeam: TeamNode; readonly operationsCommitteeTeam: TeamNode; @@ -952,7 +962,7 @@ export type MarathonResolverKeyedIsNullFilterItem = { export type MembershipNode = Node & { readonly __typename?: 'MembershipNode'; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly person: PersonNode; readonly position: MembershipPositionType; readonly team: TeamNode; @@ -1017,12 +1027,12 @@ export type Mutation = { export type MutationAbortScheduledNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationAcknowledgeDeliveryIssueArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1034,7 +1044,7 @@ export type MutationAddExistingImageToEventArgs = { export type MutationAddMapArgs = { imageUuid: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1121,17 +1131,17 @@ export type MutationCreateTeamArgs = { export type MutationDeleteConfigurationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteDeviceArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteEventArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1141,48 +1151,48 @@ export type MutationDeleteFeedItemArgs = { export type MutationDeleteFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; export type MutationDeleteImageArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteMarathonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteMarathonHourArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteNotificationArgs = { force?: InputMaybe; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePersonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePointEntryArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeletePointOpportunityArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationDeleteTeamArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1204,24 +1214,24 @@ export type MutationRemoveImageFromFeedItemArgs = { export type MutationRemoveMapArgs = { imageUuid: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationScheduleNotificationArgs = { sendAt: Scalars['DateTimeISO']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSendNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetEventArgs = { input: SetEventInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1233,42 +1243,42 @@ export type MutationSetFeedItemArgs = { export type MutationSetImageAltTextArgs = { alt: Scalars['String']['input']; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetImageUrlArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetMarathonArgs = { input: SetMarathonInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetMarathonHourArgs = { input: SetMarathonHourInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetPersonArgs = { input: SetPersonInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetPointOpportunityArgs = { input: SetPointOpportunityInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; export type MutationSetTeamArgs = { input: SetTeamInput; - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1281,12 +1291,12 @@ export type MutationStageNotificationArgs = { export type MutationUpdateFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; input: UpdateFundraisingAssignmentInput; }; export type Node = { - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; }; export type NotificationAudienceInput = { @@ -1314,7 +1324,7 @@ export type NotificationDeliveryNode = Node & { readonly createdAt?: Maybe; /** Any error message returned by Expo when sending the notification. */ readonly deliveryError?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly notification: NotificationNode; /** The time the server received a delivery receipt from the user. */ readonly receiptCheckedAt?: Maybe; @@ -1365,7 +1375,7 @@ export type NotificationNode = Node & { readonly deliveryIssue?: Maybe; readonly deliveryIssueAcknowledgedAt?: Maybe; readonly deliveryIssueCount: NotificationDeliveryIssueCount; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; /** The time the notification is scheduled to be sent, if null it is either already sent or unscheduled. */ readonly sendAt?: Maybe; /** The time the server started sending the notification. */ @@ -1450,7 +1460,7 @@ export type PersonNode = Node & { readonly dbRole: DbRole; readonly email: Scalars['String']['output']; readonly fundraisingAssignments: ReadonlyArray; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly linkblue?: Maybe; readonly moraleTeams: ReadonlyArray; readonly name?: Maybe; @@ -1528,7 +1538,7 @@ export type PointEntryNode = Node & { readonly __typename?: 'PointEntryNode'; readonly comment?: Maybe; readonly createdAt?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly personFrom?: Maybe; readonly pointOpportunity?: Maybe; readonly points: Scalars['Int']['output']; @@ -1569,7 +1579,7 @@ export type PointOpportunityNode = Node & { readonly __typename?: 'PointOpportunityNode'; readonly createdAt?: Maybe; readonly event?: Maybe; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly name: Scalars['String']['output']; readonly opportunityDate?: Maybe; readonly type: TeamType; @@ -1641,6 +1651,7 @@ export type Query = { readonly __typename?: 'Query'; readonly activeConfiguration: GetConfigurationByUuidResponse; readonly allConfigurations: GetAllConfigurationsResponse; + readonly configuration: GetConfigurationByUuidResponse; readonly currentMarathon?: Maybe; readonly currentMarathonHour?: Maybe; readonly dbFundsTeams: ReadonlyArray; @@ -1662,6 +1673,7 @@ export type Query = { readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; readonly me: GetPersonResponse; + readonly node: Node; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; @@ -1682,13 +1694,18 @@ export type QueryActiveConfigurationArgs = { }; +export type QueryConfigurationArgs = { + id: Scalars['GlobalId']['input']; +}; + + export type QueryDbFundsTeamsArgs = { search: Scalars['String']['input']; }; export type QueryDeviceArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1709,7 +1726,7 @@ export type QueryDevicesArgs = { export type QueryEventArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1735,7 +1752,7 @@ export type QueryFeedArgs = { export type QueryFundraisingAssignmentArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; @@ -1756,12 +1773,12 @@ export type QueryFundraisingEntriesArgs = { export type QueryFundraisingEntryArgs = { - id: Scalars['String']['input']; + id: Scalars['GlobalId']['input']; }; export type QueryImageArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1798,7 +1815,7 @@ export type QueryListPeopleArgs = { export type QueryMarathonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1808,7 +1825,7 @@ export type QueryMarathonForYearArgs = { export type QueryMarathonHourArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1828,8 +1845,13 @@ export type QueryMarathonsArgs = { }; +export type QueryNodeArgs = { + id: Scalars['GlobalId']['input']; +}; + + export type QueryNotificationArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1867,7 +1889,7 @@ export type QueryNotificationsArgs = { export type QueryPersonArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1893,7 +1915,7 @@ export type QueryPointEntriesArgs = { export type QueryPointEntryArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1914,7 +1936,7 @@ export type QueryPointOpportunitiesArgs = { export type QueryPointOpportunityArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -1924,7 +1946,7 @@ export type QuerySearchPeopleByNameArgs = { export type QueryTeamArgs = { - uuid: Scalars['String']['input']; + uuid: Scalars['GlobalId']['input']; }; @@ -2073,7 +2095,7 @@ export type TeamNode = Node & { readonly captains: ReadonlyArray; readonly createdAt?: Maybe; readonly fundraisingEntries: ListFundraisingEntriesResponse; - readonly id: Scalars['ID']['output']; + readonly id: Scalars['GlobalId']['output']; readonly legacyStatus: TeamLegacyStatus; readonly marathon: MarathonNode; readonly members: ReadonlyArray; @@ -2208,10 +2230,10 @@ export type SetDeviceMutationVariables = Exact<{ export type SetDeviceMutation = { readonly __typename?: 'Mutation', readonly registerDevice: { readonly __typename?: 'RegisterDeviceResponse', readonly ok: boolean } }; -export type EventScreenFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly uuid: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly thumbHash?: string | null, readonly url?: URL | string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string }> } & { ' $fragmentName'?: 'EventScreenFragmentFragment' }; +export type EventScreenFragmentFragment = { readonly __typename?: 'EventNode', readonly id: string, readonly title: string, readonly summary?: string | null, readonly description?: string | null, readonly location?: string | null, readonly occurrences: ReadonlyArray<{ readonly __typename?: 'EventOccurrenceNode', readonly id: string, readonly fullDay: boolean, readonly interval: { readonly __typename?: 'IntervalISO', readonly start: Date | string, readonly end: Date | string } }>, readonly images: ReadonlyArray<{ readonly __typename?: 'ImageNode', readonly thumbHash?: string | null, readonly url?: URL | string | null, readonly height: number, readonly width: number, readonly alt?: string | null, readonly mimeType: string }> } & { ' $fragmentName'?: 'EventScreenFragmentFragment' }; export type DeviceNotificationsQueryVariables = Exact<{ - deviceUuid: Scalars['String']['input']; + deviceUuid: Scalars['GlobalId']['input']; page?: InputMaybe; pageSize?: InputMaybe; verifier: Scalars['String']['input']; @@ -2300,7 +2322,7 @@ export const SimpleConfigFragmentDoc = {"kind":"Document","definitions":[{"kind" export const FullConfigFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}},{"kind":"Field","name":{"kind":"Name","value":"validAfter"}},{"kind":"Field","name":{"kind":"Name","value":"validUntil"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const NotificationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; export const NotificationDeliveryFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]} as unknown as DocumentNode; -export const EventScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; +export const EventScreenFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ProfileScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]} as unknown as DocumentNode; export const ProfileScreenUserFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const RootScreenAuthFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}}]} as unknown as DocumentNode; @@ -2315,9 +2337,9 @@ export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind" export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; export const SetDeviceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDevice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterDeviceInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerDevice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; +export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; -export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"asc"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; +export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"asc"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"desc"},{"kind":"EnumValue","value":"asc"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; diff --git a/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx b/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx index b4c4a7a6..fa900fe3 100644 --- a/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx +++ b/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx @@ -151,14 +151,14 @@ const EventScreen = () => { )} {eventData.occurrences.map((occurrence) => { - const highlighted = occurrence.uuid === occurrenceId; + const highlighted = occurrence.id === occurrenceId; const interval = intervalFromSomething(occurrence.interval); const { whenString, allDay } = stringifyInterval(interval); return ( diff --git a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts index 65c1a1e9..a1b951da 100644 --- a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts +++ b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts @@ -8,7 +8,7 @@ export const EventScreenFragment = graphql(/* GraphQL */ ` description location occurrences { - uuid + id interval { start end diff --git a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts index 31f7424e..92573d34 100644 --- a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts +++ b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts @@ -78,7 +78,7 @@ export async function onAddToCalendar( endTimeZone: interval.end.zoneName, organizer: "UK DanceBlue", organizerEmail: "community@danceblue.org", - id: `${eventData.id}:${occurrence.uuid}`, + id: `${eventData.id}:${occurrence.id}`, }; }; @@ -86,7 +86,7 @@ export async function onAddToCalendar( expoEvents.push(...eventData.occurrences.map(eventDataToExpoEvent)); } else { const occurrence = eventData.occurrences.find( - (o) => o.uuid === occurrenceId + (o) => o.id === occurrenceId ); if (!occurrence) { diff --git a/packages/mobile/src/navigation/root/NotificationScreen/refresh.ts b/packages/mobile/src/navigation/root/NotificationScreen/refresh.ts index a2557f3d..3ae109de 100644 --- a/packages/mobile/src/navigation/root/NotificationScreen/refresh.ts +++ b/packages/mobile/src/navigation/root/NotificationScreen/refresh.ts @@ -15,7 +15,7 @@ const INCOMPLETE_PAGE_TIMEOUT = 10_000; export const deviceNotificationsQuery = graphql(/* GraphQL */ ` query DeviceNotifications( - $deviceUuid: String! + $deviceUuid: GlobalId! $page: Int $pageSize: Int $verifier: String! diff --git a/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx b/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx index 6a2ac910..5da397d9 100644 --- a/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx +++ b/packages/mobile/src/navigation/root/tab/EventListScreen/EventListRenderItem.tsx @@ -14,7 +14,7 @@ import EventRow from "./EventRow"; import { RNCAL_DATE_FORMAT } from "./constants"; export const EventListRenderItem = ({ - item: [event, occurrenceUuid], + item: [event, occurrenceId], index, dayIndexesRef, tryToNavigate, @@ -38,7 +38,7 @@ export const EventListRenderItem = ({ const occurrence = useMemo(() => { const occurrence = eventData.occurrences.find( - (occurrence) => occurrence.uuid === occurrenceUuid + (occurrence) => occurrence.id === occurrenceId ); if (!occurrence) { return undefined; @@ -47,7 +47,7 @@ export const EventListRenderItem = ({ ...occurrence, interval: intervalFromSomething(occurrence.interval), }; - }, [occurrenceUuid, eventData.occurrences]); + }, [occurrenceId, eventData.occurrences]); const eventDate = useMemo(() => { return occurrence?.interval.start?.toFormat(RNCAL_DATE_FORMAT); @@ -60,8 +60,8 @@ export const EventListRenderItem = ({ } const onPress = useCallback(() => { - tryToNavigate(event, occurrenceUuid); - }, [event, occurrenceUuid, tryToNavigate]); + tryToNavigate(event, occurrenceId); + }, [event, occurrenceId, tryToNavigate]); return useMemo( () => ( @@ -111,7 +111,7 @@ export const EventListRenderItem = ({ } > { parseEventOccurrence(occurrence) ); return ( -
  • +
  • {startString} to {endString}
  • ); diff --git a/packages/portal/src/pages/events/single-event/edit-event/EditEventPage.tsx b/packages/portal/src/pages/events/single-event/edit-event/EditEventPage.tsx index e0af1674..67d2f58b 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/EditEventPage.tsx +++ b/packages/portal/src/pages/events/single-event/edit-event/EditEventPage.tsx @@ -6,7 +6,7 @@ import { useQuery } from "urql"; import { EventEditor } from "./EventEditor"; const viewEventPageDocument = graphql(/* GraphQL */ ` - query EditEventPage($uuid: String!) { + query EditEventPage($uuid: GlobalId!) { event(uuid: $uuid) { data { ...EventEditorFragment diff --git a/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts b/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts index fc98ce9a..dc7d9ac7 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts +++ b/packages/portal/src/pages/events/single-event/edit-event/EventEditorGQL.ts @@ -8,7 +8,7 @@ export const EventEditorFragment = graphql(/* GraphQL */ ` description location occurrences { - uuid + id interval { start end @@ -26,7 +26,7 @@ export const EventEditorFragment = graphql(/* GraphQL */ ` `); export const eventEditorDocument = graphql(/* GraphQL */ ` - mutation SaveEvent($uuid: String!, $input: SetEventInput!) { + mutation SaveEvent($uuid: GlobalId!, $input: SetEventInput!) { setEvent(uuid: $uuid, input: $input) { data { ...EventEditorFragment diff --git a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts index 243bbde3..5b28b657 100644 --- a/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts +++ b/packages/portal/src/pages/events/single-event/edit-event/useEventEditorForm.ts @@ -43,7 +43,7 @@ export function useEventEditorForm( description: eventData?.description || null, occurrences: eventData?.occurrences.map((occurrence) => ({ - uuid: occurrence.uuid, + uuid: occurrence.id, interval: intervalFromSomething(occurrence.interval), fullDay: occurrence.fullDay, })) ?? [], diff --git a/packages/portal/src/pages/events/single-event/view-event/EventDeletePopup.tsx b/packages/portal/src/pages/events/single-event/view-event/EventDeletePopup.tsx index 5d8bb4ad..8f13cd44 100644 --- a/packages/portal/src/pages/events/single-event/view-event/EventDeletePopup.tsx +++ b/packages/portal/src/pages/events/single-event/view-event/EventDeletePopup.tsx @@ -5,7 +5,7 @@ import { useEffect, useState } from "react"; import { useMutation } from "urql"; const deleteEventDocument = graphql(/* GraphQL */ ` - mutation DeleteEvent($uuid: String!) { + mutation DeleteEvent($uuid: GlobalId!) { deleteEvent(uuid: $uuid) { ok } diff --git a/packages/portal/src/pages/events/single-event/view-event/ViewEventPage.tsx b/packages/portal/src/pages/events/single-event/view-event/ViewEventPage.tsx index bb80bfbf..8b188431 100644 --- a/packages/portal/src/pages/events/single-event/view-event/ViewEventPage.tsx +++ b/packages/portal/src/pages/events/single-event/view-event/ViewEventPage.tsx @@ -6,7 +6,7 @@ import { useQuery } from "urql"; import { EventViewer } from "./EventViewer"; const viewEventPageDocument = graphql(/* GraphQL */ ` - query ViewEventPage($uuid: String!) { + query ViewEventPage($uuid: GlobalId!) { event(uuid: $uuid) { data { ...EventViewerFragment diff --git a/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts b/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts index 30fe02dc..e0f7754d 100644 --- a/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts +++ b/packages/portal/src/pages/marathon/single/edit/useMarathonEditorForm.ts @@ -11,7 +11,10 @@ export function useMarathonCreatorForm({ marathonId }: { marathonId: string }) { const [{ fetching: editFetching, error: editError }, editMarathon] = useMutation( graphql(/* GraphQL */ ` - mutation EditMarathon($input: SetMarathonInput!, $marathonId: String!) { + mutation EditMarathon( + $input: SetMarathonInput! + $marathonId: GlobalId! + ) { setMarathon(input: $input, uuid: $marathonId) { id } @@ -29,7 +32,7 @@ export function useMarathonCreatorForm({ marathonId }: { marathonId: string }) { { data: existingData, fetching: existingFetching, error: existingError }, ] = useQuery({ query: graphql(/* GraphQL */ ` - query GetMarathon($marathonId: String!) { + query GetMarathon($marathonId: GlobalId!) { marathon(uuid: $marathonId) { year startDate diff --git a/packages/portal/src/pages/marathon/single/view/ViewMarathonPage.tsx b/packages/portal/src/pages/marathon/single/view/ViewMarathonPage.tsx index 8f7a79cf..d3abf26c 100644 --- a/packages/portal/src/pages/marathon/single/view/ViewMarathonPage.tsx +++ b/packages/portal/src/pages/marathon/single/view/ViewMarathonPage.tsx @@ -5,7 +5,7 @@ import { useQuery } from "urql"; import { MarathonViewer } from "./MarathonViewer"; const marathonPageDocument = graphql(/* GraphQL */ ` - query MarathonPage($marathonUuid: String!) { + query MarathonPage($marathonUuid: GlobalId!) { marathon(uuid: $marathonUuid) { ...MarathonViewerFragment } diff --git a/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx b/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx index 6149129d..9d9fb9b2 100644 --- a/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx +++ b/packages/portal/src/pages/marathon/single/view/hour/edit/EditMarathonHourPage.tsx @@ -13,7 +13,7 @@ import type { DateTime } from "luxon"; import { useMutation, useQuery } from "urql"; const editMarathonHourDataDocument = graphql(/* GraphQL */ ` - query EditMarathonHourData($marathonHourUuid: String!) { + query EditMarathonHourData($marathonHourUuid: GlobalId!) { marathonHour(uuid: $marathonHourUuid) { details durationInfo @@ -24,7 +24,7 @@ const editMarathonHourDataDocument = graphql(/* GraphQL */ ` `); const editMarathonHourDocument = graphql(/* GraphQL */ ` - mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: String!) { + mutation EditMarathonHour($input: SetMarathonHourInput!, $uuid: GlobalId!) { setMarathonHour(input: $input, uuid: $uuid) { id } diff --git a/packages/portal/src/pages/notifications/single/manage/ManageNotificationPage.tsx b/packages/portal/src/pages/notifications/single/manage/ManageNotificationPage.tsx index 892f3195..25dca40a 100644 --- a/packages/portal/src/pages/notifications/single/manage/ManageNotificationPage.tsx +++ b/packages/portal/src/pages/notifications/single/manage/ManageNotificationPage.tsx @@ -5,7 +5,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; const notificationManagerDocument = graphql(/* GraphQL */ ` - query NotificationManager($uuid: String!) { + query NotificationManager($uuid: GlobalId!) { notification(uuid: $uuid) { data { ...SingleNotificationFragment diff --git a/packages/portal/src/pages/notifications/single/view/ViewNotificationPage.tsx b/packages/portal/src/pages/notifications/single/view/ViewNotificationPage.tsx index 8df878e1..4e8462d3 100644 --- a/packages/portal/src/pages/notifications/single/view/ViewNotificationPage.tsx +++ b/packages/portal/src/pages/notifications/single/view/ViewNotificationPage.tsx @@ -8,7 +8,7 @@ import { Button, Flex, Typography } from "antd"; import { useQuery } from "urql"; const notificationViewerDocument = graphql(/* GraphQL */ ` - query NotificationViewer($uuid: String!) { + query NotificationViewer($uuid: GlobalId!) { notification(uuid: $uuid) { data { ...SingleNotificationFragment diff --git a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx index 5e4ff9e2..3f0607b3 100644 --- a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx +++ b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx @@ -5,7 +5,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; const viewPersonPageDocument = graphql(/* GraphQL */ ` - query EditPersonPage($uuid: String!) { + query EditPersonPage($uuid: GlobalId!) { person(uuid: $uuid) { data { ...PersonEditorFragment diff --git a/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx b/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx index cfefde13..0f676764 100644 --- a/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx +++ b/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx @@ -5,7 +5,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; const viewPersonPageDocument = graphql(/* GraphQL */ ` - query ViewPersonPage($uuid: String!) { + query ViewPersonPage($uuid: GlobalId!) { person(uuid: $uuid) { data { ...PersonViewerFragment diff --git a/packages/portal/src/pages/teams/spirit/single-team/edit-team/EditTeamPage.tsx b/packages/portal/src/pages/teams/spirit/single-team/edit-team/EditTeamPage.tsx index d492d3a2..3f4ae1a5 100644 --- a/packages/portal/src/pages/teams/spirit/single-team/edit-team/EditTeamPage.tsx +++ b/packages/portal/src/pages/teams/spirit/single-team/edit-team/EditTeamPage.tsx @@ -5,7 +5,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; import { useQuery } from "urql"; const viewTeamPageDocument = graphql(/* GraphQL */ ` - query EditTeamPage($uuid: String!) { + query EditTeamPage($uuid: GlobalId!) { team(uuid: $uuid) { data { ...TeamEditorFragment diff --git a/packages/portal/src/pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising.tsx b/packages/portal/src/pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising.tsx index bd37a941..7fa8fa60 100644 --- a/packages/portal/src/pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising.tsx +++ b/packages/portal/src/pages/teams/spirit/single-team/view-team/fundraising/ViewTeamFundraising.tsx @@ -5,7 +5,7 @@ import { Flex } from "antd"; import { useQuery } from "urql"; const ViewTeamFundraisingDocument = graphql(/* GraphQL */ ` - query ViewTeamFundraisingDocument($teamUuid: String!) { + query ViewTeamFundraisingDocument($teamUuid: GlobalId!) { team(uuid: $teamUuid) { data { # TODO: Add filtering and pagination diff --git a/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx b/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx index 259cb745..01a7bfa9 100644 --- a/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx +++ b/packages/portal/src/pages/teams/spirit/single-team/view-team/teamPageDocument.tsx @@ -1,7 +1,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const teamPageDocument = graphql(/* GraphQL */ ` - query ViewTeamPage($teamUuid: String!) { + query ViewTeamPage($teamUuid: GlobalId!) { team(uuid: $teamUuid) { data { ...TeamViewerFragment From 3e38c597b0cf17cee657e27f4c16ae51a7454cab Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 1 Jul 2024 17:34:44 +0000 Subject: [PATCH 130/153] Refactor error classes to use tags for better error handling --- packages/server/src/lib/error/composite.ts | 9 ++ packages/server/src/lib/error/control.ts | 27 +++++ packages/server/src/lib/error/direct.ts | 122 +++++++++++++++++++++ packages/server/src/lib/error/error.ts | 20 ++++ packages/server/src/lib/error/http.ts | 9 ++ packages/server/src/lib/error/prisma.ts | 12 ++ packages/server/src/lib/error/zod.ts | 9 ++ 7 files changed, 208 insertions(+) diff --git a/packages/server/src/lib/error/composite.ts b/packages/server/src/lib/error/composite.ts index 814b74fc..26b0e981 100644 --- a/packages/server/src/lib/error/composite.ts +++ b/packages/server/src/lib/error/composite.ts @@ -1,5 +1,7 @@ import { ConcreteError } from "./error.js"; +const CompositeErrorTag = Symbol("CompositeError"); +type CompositeErrorTag = typeof CompositeErrorTag; export class CompositeError extends ConcreteError { readonly errors: E[]; @@ -19,4 +21,11 @@ export class CompositeError extends ConcreteError { get expose(): boolean { return this.errors.every((error) => error.expose); } + + static get Tag() { + return CompositeErrorTag; + } + get tag(): CompositeErrorTag { + return CompositeErrorTag; + } } diff --git a/packages/server/src/lib/error/control.ts b/packages/server/src/lib/error/control.ts index fda22203..d49b8f0e 100644 --- a/packages/server/src/lib/error/control.ts +++ b/packages/server/src/lib/error/control.ts @@ -23,6 +23,8 @@ export abstract class ControlError extends ConcreteError { } } +const UnauthorizedErrorTag = Symbol("UnauthorizedError"); +type UnauthorizedErrorTag = typeof UnauthorizedErrorTag; export class UnauthorizedError extends ControlError { get message() { return "Unauthorized"; @@ -35,14 +37,32 @@ export class UnauthorizedError extends ControlError { get detailedMessage() { return `Unauthorized: ${this.requiredAuthorization.map(prettyPrintAuthorizationRule).join(", ")}`; } + + static get Tag(): UnauthorizedErrorTag { + return UnauthorizedErrorTag; + } + get tag(): UnauthorizedErrorTag { + return UnauthorizedErrorTag; + } } +const UnauthenticatedErrorTag = Symbol("UnauthenticatedError"); +type UnauthenticatedErrorTag = typeof UnauthenticatedErrorTag; export class UnauthenticatedError extends ControlError { get message() { return "Unauthenticated"; } + + static get Tag(): UnauthenticatedErrorTag { + return UnauthenticatedErrorTag; + } + get tag(): UnauthenticatedErrorTag { + return UnauthenticatedErrorTag; + } } +const ActionDeniedErrorTag = Symbol("ActionDeniedError"); +type ActionDeniedErrorTag = typeof ActionDeniedErrorTag; export class ActionDeniedError extends ControlError { constructor(protected readonly action: string) { super(); @@ -51,4 +71,11 @@ export class ActionDeniedError extends ControlError { get message() { return `Action denied: ${this.action}`; } + + static get Tag(): ActionDeniedErrorTag { + return ActionDeniedErrorTag; + } + get tag(): ActionDeniedErrorTag { + return ActionDeniedErrorTag; + } } diff --git a/packages/server/src/lib/error/direct.ts b/packages/server/src/lib/error/direct.ts index 338807fe..4476ead7 100644 --- a/packages/server/src/lib/error/direct.ts +++ b/packages/server/src/lib/error/direct.ts @@ -2,6 +2,8 @@ import { Maybe } from "true-myth"; import { ConcreteError } from "./error.js"; +const NotFoundErrorTag = Symbol("NotFoundError"); +type NotFoundErrorTag = typeof NotFoundErrorTag; export class NotFoundError extends ConcreteError { readonly #what: Maybe; readonly #where: Maybe; @@ -47,8 +49,17 @@ export class NotFoundError extends ConcreteError { get stack(): string | undefined { return undefined; } + + static get Tag(): NotFoundErrorTag { + return NotFoundErrorTag; + } + get tag(): NotFoundErrorTag { + return NotFoundErrorTag; + } } +const TimeoutErrorTag = Symbol("TimeoutError"); +type TimeoutErrorTag = typeof TimeoutErrorTag; export class TimeoutError extends ConcreteError { readonly #what: string | null; @@ -64,4 +75,115 @@ export class TimeoutError extends ConcreteError { get expose() { return false; } + + static get Tag(): TimeoutErrorTag { + return TimeoutErrorTag; + } + get tag(): TimeoutErrorTag { + return TimeoutErrorTag; + } +} + +const NotImplementedErrorTag = Symbol("NotImplementedError"); +type NotImplementedErrorTag = typeof NotImplementedErrorTag; +export class InvalidOperationError extends ConcreteError { + readonly #what: string; + + constructor(what: string) { + super(); + this.#what = what; + } + + get message(): string { + return `Invalid operation: ${this.#what}`; + } + + get expose() { + return false; + } + + static get Tag(): NotImplementedErrorTag { + return NotImplementedErrorTag; + } + get tag(): NotImplementedErrorTag { + return NotImplementedErrorTag; + } +} + +const InvalidArgumentErrorTag = Symbol("InvalidArgumentError"); +type InvalidArgumentErrorTag = typeof InvalidArgumentErrorTag; +export class InvalidArgumentError extends ConcreteError { + readonly #what: string; + + constructor(what: string) { + super(); + this.#what = what; + } + + get message(): string { + return `Invalid argument: ${this.#what}`; + } + + get expose() { + return false; + } + + static get Tag(): InvalidArgumentErrorTag { + return InvalidArgumentErrorTag; + } + get tag(): InvalidArgumentErrorTag { + return InvalidArgumentErrorTag; + } +} + +const InvalidStateErrorTag = Symbol("InvalidStateError"); +type InvalidStateErrorTag = typeof InvalidStateErrorTag; +export class InvalidStateError extends ConcreteError { + readonly #what: string; + + constructor(what: string) { + super(); + this.#what = what; + } + + get message(): string { + return `Invalid state: ${this.#what}`; + } + + get expose() { + return false; + } + + static get Tag(): InvalidStateErrorTag { + return InvalidStateErrorTag; + } + get tag(): InvalidStateErrorTag { + return InvalidStateErrorTag; + } +} + +const InvariantErrorTag = Symbol("InvariantError"); +type InvariantErrorTag = typeof InvariantErrorTag; +export class InvariantError extends ConcreteError { + readonly #what: string; + + constructor(what: string) { + super(); + this.#what = what; + } + + get message(): string { + return `Invariant violation: ${this.#what}`; + } + + get expose() { + return false; + } + + static get Tag(): InvariantErrorTag { + return InvariantErrorTag; + } + get tag(): InvariantErrorTag { + return InvariantErrorTag; + } } diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index ea461dbc..2db2c767 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -10,8 +10,11 @@ export abstract class ConcreteError { get stack(): string | undefined { return undefined; } + abstract get tag(): unknown; } +const JsErrorTag = Symbol("JsError"); +type JsErrorTag = typeof JsErrorTag; export class JsError extends ConcreteError { readonly error: Error; @@ -31,8 +34,18 @@ export class JsError extends ConcreteError { get stack(): string | undefined { return this.error.stack; } + + static get Tag(): JsErrorTag { + return JsErrorTag; + } + + get tag(): JsErrorTag { + return JsErrorTag; + } } +const UnknownErrorTag = Symbol("UnknownError"); +type UnknownErrorTag = typeof UnknownErrorTag; export class UnknownError extends ConcreteError { readonly #message: string = "Unknown error"; @@ -51,6 +64,13 @@ export class UnknownError extends ConcreteError { get expose(): boolean { return false; } + + static get Tag(): UnknownErrorTag { + return UnknownErrorTag; + } + get tag(): UnknownErrorTag { + return UnknownErrorTag; + } } export type BasicError = JsError | UnknownError; diff --git a/packages/server/src/lib/error/http.ts b/packages/server/src/lib/error/http.ts index b0f3db07..e8cdd889 100644 --- a/packages/server/src/lib/error/http.ts +++ b/packages/server/src/lib/error/http.ts @@ -3,6 +3,8 @@ import { getReasonPhrase } from "http-status-codes"; import { ConcreteError } from "./error.js"; +const HttpErrorTag = Symbol("HttpError"); +type HttpErrorTag = typeof HttpErrorTag; export class HttpError< Code extends StatusCodes = StatusCodes, > extends ConcreteError { @@ -17,4 +19,11 @@ export class HttpError< get expose(): boolean { return true; } + + static get Tag(): HttpErrorTag { + return HttpErrorTag; + } + get tag(): HttpErrorTag { + return HttpErrorTag; + } } diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts index ac0297ff..4545c0a5 100644 --- a/packages/server/src/lib/error/prisma.ts +++ b/packages/server/src/lib/error/prisma.ts @@ -6,6 +6,7 @@ import { PrismaClientValidationError, } from "@prisma/client/runtime/library"; import { Maybe } from "true-myth"; +import type { Just } from "true-myth/maybe"; import { ConcreteError } from "./error.js"; @@ -16,6 +17,8 @@ type RawPrismaError = | PrismaClientInitializationError | PrismaClientValidationError; +const PrismaErrorTag = Symbol("PrismaError"); +type PrismaErrorTag = typeof PrismaErrorTag; export abstract class PrismaError extends ConcreteError { readonly error: RawPrismaError; @@ -35,6 +38,13 @@ export abstract class PrismaError extends ConcreteError { get expose(): boolean { return false; } + + static get Tag(): PrismaErrorTag { + return PrismaErrorTag; + } + get tag(): PrismaErrorTag { + return PrismaErrorTag; + } } export class PrismaKnownRequestError extends PrismaError { @@ -89,6 +99,8 @@ export type SomePrismaError = | PrismaUnknownRequestError | PrismaValidationError; +export function toPrismaError(error: RawPrismaError): Just; +export function toPrismaError(error: unknown): Maybe; export function toPrismaError(error: unknown): Maybe { if (error instanceof PrismaClientInitializationError) { return Maybe.of(new PrismaInitializationError(error)); diff --git a/packages/server/src/lib/error/zod.ts b/packages/server/src/lib/error/zod.ts index 354148b9..3494a000 100644 --- a/packages/server/src/lib/error/zod.ts +++ b/packages/server/src/lib/error/zod.ts @@ -2,6 +2,8 @@ import type { ZodError as RawZodError } from "zod"; import { ConcreteError } from "./error.js"; +const ZodErrorTag = Symbol("ZodError"); +type ZodErrorTag = typeof ZodErrorTag; export class ZodError extends ConcreteError { readonly error: RawZodError; constructor(error: RawZodError) { @@ -14,4 +16,11 @@ export class ZodError extends ConcreteError { get expose() { return false; } + + static get Tag() { + return ZodErrorTag; + } + get tag(): ZodErrorTag { + return ZodErrorTag; + } } From 92896da1b8b492d972b5caf19cfff9a9ab0ddbb4 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Mon, 1 Jul 2024 17:35:04 +0000 Subject: [PATCH 131/153] Do a pass with true-myth over the repositories --- .../committee/CommitteeRepository.ts | 292 ++++++++++++------ .../fundraising/DBFundsRepository.ts | 6 +- .../fundraising/FundraisingRepository.ts | 1 - .../marathon/MarathonRepository.ts | 123 +++++--- .../membership/MembershipRepository.ts | 265 ++++++++++------ packages/server/src/repositories/shared.ts | 5 + .../server/src/resolvers/MarathonResolver.ts | 46 +-- .../src/resolvers/MembershipResolver.ts | 32 +- packages/server/src/resolvers/NodeResolver.ts | 3 +- .../server/src/resolvers/PersonResolver.ts | 24 +- 10 files changed, 489 insertions(+), 308 deletions(-) diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index c0bf9f7c..c31c9785 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -1,18 +1,22 @@ -import { Prisma, PrismaClient } from "@prisma/client"; +import { Committee, Prisma, PrismaClient, Team } from "@prisma/client"; import { CommitteeIdentifier, CommitteeRole, - DetailedError, - ErrorCode, SortDirection, } from "@ukdanceblue/common"; +import { Result, Unit } from "true-myth"; +import { err, ok } from "true-myth/result"; import { Service } from "typedi"; +import { CompositeError } from "../../lib/error/composite.js"; +import { InvariantError, NotFoundError } from "../../lib/error/direct.js"; +import { toBasicError } from "../../lib/error/error.js"; +import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { MembershipRepository } from "../membership/MembershipRepository.js"; -import type { SimpleUniqueParam } from "../shared.js"; +import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; import * as CommitteeDescriptions from "./committeeDescriptions.js"; import { @@ -54,25 +58,40 @@ export class CommitteeRepository { // Finders - findCommittees( + async findCommittees( filters: readonly CommitteeFilters[] | null | undefined, order: readonly [key: string, sort: SortDirection][] | null | undefined, limit?: number | undefined, offset?: number | undefined - ) { - const where = buildCommitteeWhere(filters); - const orderBy = buildCommitteeOrder(order); - - return this.prisma.committee.findMany({ - where, - orderBy, - take: limit, - skip: offset, - }); + ): Promise> { + try { + const where = buildCommitteeWhere(filters); + const orderBy = buildCommitteeOrder(order); + + const committees = await this.prisma.committee.findMany({ + where, + orderBy, + take: limit, + skip: offset, + }); + + return ok(committees); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - findCommitteeByUnique(param: CommitteeUniqueParam) { - return this.prisma.committee.findUnique({ where: param }); + async findCommitteeByUnique( + param: CommitteeUniqueParam + ): Promise> { + try { + const committee = await this.prisma.committee.findUnique({ + where: param, + }); + return ok(committee); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async assignPersonToCommittee( @@ -80,123 +99,202 @@ export class CommitteeRepository { committeeParam: CommitteeIdentifier, committeeRole: CommitteeRole, marathonParam?: UniqueMarathonParam - ) { - const person = await this.prisma.person.findUnique({ where: personParam }); - if (!person) { - throw new DetailedError(ErrorCode.NotFound, "Person not found"); - } + ): Promise>> { + try { + const person = await this.prisma.person.findUnique({ + where: personParam, + }); + if (!person) { + return err(new NotFoundError({ what: "Person" })); + } - if (!marathonParam) { - const latestMarathon = await this.marathonRepository.findActiveMarathon(); - if (!latestMarathon) { - throw new DetailedError( - ErrorCode.NotFound, - "No upcoming marathon found and no marathon provided" - ); + if (!marathonParam) { + const latestMarathon = + await this.marathonRepository.findActiveMarathon(); + if (latestMarathon.isErr) { + return err(latestMarathon.error); + } + marathonParam = { id: latestMarathon.value.id }; + } else { + const val = + await this.marathonRepository.findMarathonByUnique(marathonParam); + if (val.isErr) { + return err(val.error); + } } - marathonParam = { id: latestMarathon.id }; - } else { - // Check if the marathon exists - const val = - await this.marathonRepository.findMarathonByUnique(marathonParam); - if (!val) { - throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); + + const committee = await this.getCommittee(committeeParam, { + forMarathon: marathonParam, + }); + + if (committee.isErr) { + return err(committee.error); } - } - const committee = await this.getCommittee(committeeParam, { - forMarathon: marathonParam, - }); + // for (const team of committee.value.correspondingTeams) { + // // eslint-disable-next-line no-await-in-loop + // await this.membershipRepository.assignPersonToTeam({ + // personParam: { id: person.id }, + // teamParam: { id: team.id }, + // committeeRole, + // }); + // } + const results = await Promise.allSettled( + committee.value.correspondingTeams.map((team) => + this.membershipRepository.assignPersonToTeam({ + personParam: { id: person.id }, + teamParam: { id: team.id }, + committeeRole, + }) + ) + ); + + const errors: RepositoryError[] = []; - for (const team of committee.correspondingTeams) { - // eslint-disable-next-line no-await-in-loop - await this.membershipRepository.assignPersonToTeam({ - personParam: { id: person.id }, - teamParam: { id: team.id }, - committeeRole, - }); + for (const result of results) { + if (result.status === "fulfilled") { + if (result.value.isErr) { + errors.push(result.value.error); + } + } else { + errors.push(toBasicError(result.reason)); + } + } + + if (errors.length > 0) { + return err(new CompositeError(errors)); + } + + return ok(); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } // Mutators - deleteCommittee(uuid: string) { + async deleteCommittee( + uuid: string + ): Promise> { try { - return this.prisma.committee.delete({ where: { uuid } }); + await this.prisma.committee.delete({ where: { uuid } }); + return ok(); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return null; + return ok(null); } else { - throw error; + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); } } } // Committee getter - getCommittee( + async getCommittee( identifier: CommitteeIdentifier, opts: { forMarathon?: UniqueMarathonParam; } = {} - ) { - return this.prisma.committee.upsert({ - ...CommitteeDescriptions[identifier], - where: { identifier }, - include: { - correspondingTeams: opts.forMarathon - ? { - where: { - marathon: opts.forMarathon, - }, - } - : undefined, + ): Promise< + Result< + Committee & { + correspondingTeams: Team[]; }, - }); + RepositoryError + > + > { + try { + const committee = await this.prisma.committee.upsert({ + ...CommitteeDescriptions[identifier], + where: { identifier }, + include: { + correspondingTeams: opts.forMarathon + ? { + where: { + marathon: opts.forMarathon, + }, + } + : undefined, + }, + }); + + return ok(committee); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async getCommitteeTeam( committee: CommitteeIdentifier, marathon: UniqueMarathonParam - ) { - const result = await this.prisma.committee - .findUnique({ where: { identifier: committee } }) - .correspondingTeams({ - where: { - marathon, - }, - }); - if (result?.length === 1) { - return result[0]; - } else if (result?.length === 0) { - throw new DetailedError( - ErrorCode.NotFound, - "No team found for the given committee and marathon" - ); - } else { - throw new DetailedError( - ErrorCode.InternalFailure, - "Multiple teams found for the given committee and marathon" - ); + ): Promise> { + try { + const result = await this.prisma.committee + .findUnique({ where: { identifier: committee } }) + .correspondingTeams({ + where: { + marathon, + }, + }); + + if (result?.length === 1) { + return ok(result[0]!); + } else if (result?.length === 0) { + return err( + new NotFoundError({ + what: "Team", + where: `Committee: ${committee}, Marathon: ${JSON.stringify(marathon)}`, + }) + ); + } else { + return err( + new InvariantError( + "Multiple teams found for the given committee and marathon" + ) + ); + } + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } - getChildCommittees(identifier: CommitteeUniqueParam) { - return this.prisma.committee - .findUnique({ - where: identifier, - }) - .childCommittees(); + async getChildCommittees( + identifier: CommitteeUniqueParam + ): Promise> { + try { + const childCommittees = await this.prisma.committee + .findUnique({ + where: identifier, + }) + .childCommittees(); + if (!childCommittees) { + return err(new NotFoundError({ what: "Committee" })); + } + + return ok(childCommittees); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - getParentCommittee(identifier: CommitteeUniqueParam) { - return this.prisma.committee - .findUnique({ - where: identifier, - }) - .parentCommittee(); + async getParentCommittee( + identifier: CommitteeUniqueParam + ): Promise> { + try { + const parentCommittee = await this.prisma.committee + .findUnique({ + where: identifier, + }) + .parentCommittee(); + + return ok(parentCommittee); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } } diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index d6add06d..82d41cd0 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -63,10 +63,10 @@ export class DBFundsRepository { } else { const marathon = await this.marathonRepository.findMarathonByUnique(marathonParam); - if (!marathon) { - return Result.err(new NotFoundError({ what: "Marathon" })); + if (marathon.isErr) { + return marathon.cast(); } - marathonId = marathon.id; + marathonId = marathon.value.id; } let dBFundsTeam = await this.prisma.dBFundsTeam.findUnique({ diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 5ba8a9ad..54d01a06 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -362,7 +362,6 @@ export class FundraisingEntryRepository { new Prisma.Decimal(0) ); if ( - assignment.parentEntry.dbFundsEntry && assignment.parentEntry.dbFundsEntry.amount.lessThan( totalAssigned.add(amount) ) diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 4b93eafa..ed9bad84 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -1,8 +1,14 @@ -import { Prisma, PrismaClient } from "@prisma/client"; +import { Marathon, MarathonHour, Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; +import { Result } from "true-myth"; +import { err, ok } from "true-myth/result"; import { Service } from "typedi"; +import { NotFoundError } from "../../lib/error/direct.js"; +import { toBasicError } from "../../lib/error/error.js"; +import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { RepositoryError } from "../shared.js"; import { buildMarathonOrder, @@ -58,21 +64,47 @@ export type UniqueMarathonParam = export class MarathonRepository { constructor(private prisma: PrismaClient) {} - findMarathonByUnique(param: UniqueMarathonParam) { - return this.prisma.marathon.findUnique({ where: param }); + async findMarathonByUnique( + param: UniqueMarathonParam + ): Promise> { + try { + const row = await this.prisma.marathon.findUnique({ where: param }); + if (!row) { + return err(new NotFoundError({ what: "Marathon" })); + } + return ok(row); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - findCurrentMarathon() { - return this.prisma.marathon.findFirst({ - orderBy: { year: "asc" }, - where: { startDate: { lte: new Date() }, endDate: { gte: new Date() } }, - }); + async findCurrentMarathon(): Promise> { + try { + const marathon = await this.prisma.marathon.findFirst({ + orderBy: { year: "asc" }, + where: { startDate: { lte: new Date() }, endDate: { gte: new Date() } }, + }); + if (!marathon) { + return err(new NotFoundError({ what: "Marathon" })); + } + return ok(marathon); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - findActiveMarathon() { - return this.prisma.marathon.findFirst({ - orderBy: { year: "asc" }, - }); + async findActiveMarathon(): Promise> { + try { + const marathon = await this.prisma.marathon.findFirst({ + orderBy: { year: "asc" }, + }); + if (!marathon) { + return err(new NotFoundError({ what: "Marathon" })); + } + return ok(marathon); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } listMarathons({ @@ -110,15 +142,21 @@ export class MarathonRepository { return this.prisma.marathon.count({ where }); } - async getMarathonHours(param: UniqueMarathonParam) { - const rows = await this.prisma.marathon.findUnique({ - where: param, - include: { hours: true }, - }); - return rows?.hours ?? []; + async getMarathonHours( + param: UniqueMarathonParam + ): Promise> { + try { + const rows = await this.prisma.marathon.findUnique({ + where: param, + include: { hours: true }, + }); + return ok(rows?.hours ?? []); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - createMarathon({ + async createMarathon({ year, startDate, endDate, @@ -126,17 +164,22 @@ export class MarathonRepository { year: string; startDate: string; endDate: string; - }) { - return this.prisma.marathon.create({ - data: { - year, - startDate, - endDate, - }, - }); + }): Promise> { + try { + const marathon = await this.prisma.marathon.create({ + data: { + year, + startDate, + endDate, + }, + }); + return ok(marathon); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - updateMarathon( + async updateMarathon( param: UniqueMarathonParam, { year, @@ -147,9 +190,9 @@ export class MarathonRepository { startDate?: string; endDate?: string; } - ) { + ): Promise> { try { - return this.prisma.marathon.update({ + const marathon = await this.prisma.marathon.update({ where: param, data: { year, @@ -157,29 +200,37 @@ export class MarathonRepository { endDate, }, }); + return ok(marathon); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return null; + return err(new NotFoundError({ what: "Marathon" })); } else { - throw error; + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); } } } - deleteMarathon(param: UniqueMarathonParam) { + async deleteMarathon( + param: UniqueMarathonParam + ): Promise> { try { - return this.prisma.marathon.delete({ where: param }); + const marathon = await this.prisma.marathon.delete({ where: param }); + return ok(marathon); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return null; + return err(new NotFoundError({ what: "Marathon" })); } else { - throw error; + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); } } } diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index 4ac0af76..12d8f291 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,9 +1,14 @@ -import { Prisma, PrismaClient } from "@prisma/client"; +import { Membership, Person, PrismaClient, Team } from "@prisma/client"; import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; +import { Result } from "true-myth"; +import { err, ok } from "true-myth/result"; import { Service } from "typedi"; +import { NotFoundError } from "../../lib/error/direct.js"; +import { toBasicError } from "../../lib/error/error.js"; +import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { SimpleUniqueParam } from "../shared.js"; +import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; const membershipBooleanKeys = [] as const; type MembershipBooleanKey = (typeof membershipBooleanKeys)[number]; @@ -38,50 +43,111 @@ type UniqueMembershipParam = { id: number } | { uuid: string }; export class MembershipRepository { constructor(private prisma: PrismaClient) {} - findMembershipByUnique( + async findMembershipByUnique( param: UniqueMembershipParam, - include: Prisma.MembershipInclude - ) { - return this.prisma.membership.findUnique({ where: param, include }); + include?: { + person?: false; + team?: false; + } + ): Promise>; + async findMembershipByUnique( + param: UniqueMembershipParam, + include: { + person: true; + team?: false; + } + ): Promise>; + async findMembershipByUnique( + param: UniqueMembershipParam, + include: { + person?: false; + team: true; + } + ): Promise>; + async findMembershipByUnique( + param: UniqueMembershipParam, + include: { + person: true; + team: true; + } + ): Promise< + Result + >; + async findMembershipByUnique( + param: UniqueMembershipParam, + include?: { + person?: boolean; + team?: boolean; + } + ): Promise< + Result< + | Membership + | (Membership & { + person: Person; + }) + | (Membership & { + team: Team; + }) + | (Membership & { + person: Person; + team: Team; + }), + RepositoryError + > + > { + try { + const membership = await this.prisma.membership.findUnique({ + where: param, + include, + }); + if (!membership) { + return err(new NotFoundError({ what: "Membership" })); + } + return ok(membership); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } private async lookupPersonAndTeamId( personParam: SimpleUniqueParam, teamParam: SimpleUniqueParam - ) { - let personId, teamId; - if ("id" in personParam) { - personId = personParam.id; - } else if ("uuid" in personParam) { - const found = await this.prisma.person.findUnique({ - where: { uuid: personParam.uuid }, - select: { id: true }, - }); - if (found == null) { - return null; + ): Promise> { + try { + let personId, teamId; + if ("id" in personParam) { + personId = personParam.id; + } else if ("uuid" in personParam) { + const found = await this.prisma.person.findUnique({ + where: { uuid: personParam.uuid }, + select: { id: true }, + }); + if (found == null) { + return err(new NotFoundError({ what: "Person" })); + } + personId = found.id; + } else { + throw new Error("Must provide either UUID or ID"); } - personId = found.id; - } else { - // teamParam satisfies Record; - throw new Error("Must provide either UUID or ID"); - } - if ("id" in teamParam) { - teamId = teamParam.id; - } else if ("uuid" in teamParam) { - const found = await this.prisma.team.findUnique({ - where: teamParam, - select: { id: true }, - }); - if (found == null) { - return null; + if ("id" in teamParam) { + teamId = teamParam.id; + } else if ("uuid" in teamParam) { + const found = await this.prisma.team.findUnique({ + where: teamParam, + select: { id: true }, + }); + if (found == null) { + return err(new NotFoundError({ what: "Team" })); + } + teamId = found.id; + } else { + throw new Error("Must provide either UUID or ID"); } - teamId = found.id; - } else { - teamParam satisfies Record; - throw new Error("Must provide either UUID or ID"); - } - return { personId, teamId }; + return ok({ personId, teamId }); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async assignPersonToTeam({ @@ -98,75 +164,84 @@ export class MembershipRepository { | { committeeRole: CommitteeRole; } - )) { - const result = await this.lookupPersonAndTeamId(personParam, teamParam); - if (result == null) { - return null; - } - const { personId, teamId } = result; - - let position: MembershipPositionType; - let committeeRole: CommitteeRole | undefined; - if ("position" in additionalData) { - // eslint-disable-next-line prefer-destructuring - position = additionalData.position; - } else if ("committeeRole" in additionalData) { - // eslint-disable-next-line prefer-destructuring - committeeRole = additionalData.committeeRole; - position = - additionalData.committeeRole === CommitteeRole.Chair - ? MembershipPositionType.Captain - : MembershipPositionType.Member; - } else { - additionalData satisfies Record; - throw new Error("Must provide either position or committeeRole"); - } + )): Promise> { + try { + const result = await this.lookupPersonAndTeamId(personParam, teamParam); + if (result.isErr) { + return err(result.error); + } + const { personId, teamId } = result.value; + + let position: MembershipPositionType; + let committeeRole: CommitteeRole | undefined; + if ("position" in additionalData) { + position = additionalData.position; + } else if ("committeeRole" in additionalData) { + committeeRole = additionalData.committeeRole; + position = + additionalData.committeeRole === CommitteeRole.Chair + ? MembershipPositionType.Captain + : MembershipPositionType.Member; + } else { + throw new Error("Must provide either position or committeeRole"); + } - return this.prisma.membership.upsert({ - where: { - personId_teamId: { - personId, - teamId, - }, - team: { - correspondingCommitteeId: null, - }, - }, - create: { - person: { - connect: { - id: personId, + const membership = await this.prisma.membership.upsert({ + where: { + personId_teamId: { + personId, + teamId, + }, + team: { + correspondingCommitteeId: null, }, }, - team: { - connect: { - id: teamId, + create: { + person: { + connect: { + id: personId, + }, }, + team: { + connect: { + id: teamId, + }, + }, + position, + committeeRole, }, - position, - committeeRole, - }, - update: {}, - }); + update: {}, + }); + + return ok(membership); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async removePersonFromTeam( personParam: SimpleUniqueParam, teamParam: SimpleUniqueParam - ) { - const result = await this.lookupPersonAndTeamId(personParam, teamParam); - if (result == null) { - return null; - } - const { personId, teamId } = result; + ): Promise> { + try { + const result = await this.lookupPersonAndTeamId(personParam, teamParam); + if (result.isErr) { + return err(result.error); + } + const { personId, teamId } = result.value; - return this.prisma.membership.delete({ - where: { - personId_teamId: { - personId, - teamId, + const membership = await this.prisma.membership.delete({ + where: { + personId_teamId: { + personId, + teamId, + }, }, - }, - }); + }); + + return ok(membership); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } } diff --git a/packages/server/src/repositories/shared.ts b/packages/server/src/repositories/shared.ts index f2e9ee83..58d801b0 100644 --- a/packages/server/src/repositories/shared.ts +++ b/packages/server/src/repositories/shared.ts @@ -1 +1,6 @@ +import type { NotFoundError } from "../lib/error/direct.js"; +import type { BasicError } from "../lib/error/error.js"; +import type { SomePrismaError } from "../lib/error/prisma.js"; + export type SimpleUniqueParam = { id: number } | { uuid: string }; +export type RepositoryError = SomePrismaError | BasicError | NotFoundError; diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 73392e3f..8c51109e 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -1,8 +1,6 @@ import type { GlobalId } from "@ukdanceblue/common"; import { CommitteeIdentifier, - DetailedError, - ErrorCode, FilteredListQueryArgs, GlobalIdScalar, MarathonHourNode, @@ -26,6 +24,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { ConcreteResult } from "../lib/error/result.js"; import { CommitteeRepository } from "../repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; @@ -86,7 +85,7 @@ export class MarathonResolver implements Record< `${CommitteeIdentifier}Team`, - (marathon: MarathonNode) => Promise + (marathon: MarathonNode) => Promise> > { constructor( @@ -99,10 +98,7 @@ export class MarathonResolver const marathon = await this.marathonRepository.findMarathonByUnique({ uuid: id, }); - if (marathon == null) { - throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); - } - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Query(() => MarathonNode) @@ -110,10 +106,7 @@ export class MarathonResolver const marathon = await this.marathonRepository.findMarathonByUnique({ year, }); - if (marathon == null) { - throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); - } - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Query(() => ListMarathonsResponse) @@ -145,25 +138,19 @@ export class MarathonResolver @Query(() => MarathonNode, { nullable: true }) async currentMarathon() { const marathon = await this.marathonRepository.findCurrentMarathon(); - if (marathon == null) { - return null; - } - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Query(() => MarathonNode, { nullable: true }) async latestMarathon() { const marathon = await this.marathonRepository.findActiveMarathon(); - if (marathon == null) { - return null; - } - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Mutation(() => MarathonNode) async createMarathon(@Arg("input") input: CreateMarathonInput) { const marathon = await this.marathonRepository.createMarathon(input); - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Mutation(() => MarathonNode) @@ -175,18 +162,13 @@ export class MarathonResolver { uuid: id }, input ); - if (marathon == null) { - throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); - } - return marathonModelToResource(marathon); + return marathon.map(marathonModelToResource); } @Mutation(() => VoidResolver) async deleteMarathon(@Arg("uuid", () => GlobalIdScalar) { id }: GlobalId) { const marathon = await this.marathonRepository.deleteMarathon({ uuid: id }); - if (marathon == null) { - throw new DetailedError(ErrorCode.NotFound, "Marathon not found"); - } + return marathon.map(marathonModelToResource); } @FieldResolver(() => [MarathonHourNode]) @@ -194,7 +176,7 @@ export class MarathonResolver const rows = await this.marathonRepository.getMarathonHours({ uuid: id, }); - return rows.map(marathonHourModelToResource); + return rows.map((hours) => hours.map(marathonHourModelToResource)); } async #committeeTeam( @@ -204,13 +186,7 @@ export class MarathonResolver const result = await this.committeeRepository.getCommitteeTeam(committee, { uuid: id, }); - if (result == null) { - throw new DetailedError( - ErrorCode.NotFound, - "No team found for the given committee and marathon" - ); - } - return teamModelToResource(result); + return result.map(teamModelToResource); } // Committees diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 54d4e539..9368e2b1 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -1,13 +1,9 @@ -import { - DetailedError, - ErrorCode, - MembershipNode, - PersonNode, - TeamNode, -} from "@ukdanceblue/common"; +import { MembershipNode, PersonNode, TeamNode } from "@ukdanceblue/common"; import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; +import { flipPromise } from "../lib/error/error.js"; +import { ConcreteResult } from "../lib/error/result.js"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; @@ -21,7 +17,9 @@ export class MembershipResolver { ) {} @FieldResolver(() => PersonNode) - async person(@Root() { id: { id } }: MembershipNode): Promise { + async person( + @Root() { id: { id } }: MembershipNode + ): Promise> { const row = await this.membershipRepository.findMembershipByUnique( { uuid: id }, { @@ -29,15 +27,15 @@ export class MembershipResolver { } ); - if (row == null) { - throw new DetailedError(ErrorCode.NotFound, "$1Node not found"); - } - - return personModelToResource(row.person, this.personRepository); + return flipPromise( + row.map((row) => personModelToResource(row.person, this.personRepository)) + ); } @FieldResolver(() => TeamNode) - async team(@Root() { id: { id } }: MembershipNode): Promise { + async team( + @Root() { id: { id } }: MembershipNode + ): Promise> { const row = await this.membershipRepository.findMembershipByUnique( { uuid: id }, { @@ -45,10 +43,6 @@ export class MembershipResolver { } ); - if (row == null) { - throw new DetailedError(ErrorCode.NotFound, "$1Node not found"); - } - - return teamModelToResource(row.team); + return row.map((row) => teamModelToResource(row.team)); } } diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 7ff837bb..040506de 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -94,8 +94,7 @@ export class NodeResolver { return ok(data); } case MarathonNode.constructor.name: { - const data = await this.marathonResolver.marathon(id); - return ok(data); + return this.marathonResolver.marathon(id); } case NotificationNode.constructor.name: { const { data } = await this.notificationResolver.getByUuid(id); diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 6e8a63ad..6d88f8f7 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -34,6 +34,7 @@ import { import { Container, Service } from "typedi"; import { NotFoundError } from "../lib/error/direct.js"; +import { ConcreteResult } from "../lib/error/result.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; @@ -75,13 +76,6 @@ class GetPersonResponse extends AbstractGraphQLOkResponse { @Field(() => PersonNode, { nullable: true }) data!: PersonNode; } -@ObjectType("GetMembershipResponse", { - implements: AbstractGraphQLOkResponse, -}) -class GetMembershipResponse extends AbstractGraphQLOkResponse { - @Field(() => MembershipNode, { nullable: true }) - data!: MembershipNode | null; -} @ObjectType("GetPeopleResponse", { implements: AbstractGraphQLArrayOkResponse, }) @@ -303,11 +297,11 @@ export class PersonResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => GetMembershipResponse, { name: "addPersonToTeam" }) + @Mutation(() => MembershipNode, { name: "addPersonToTeam" }) async assignPersonToTeam( @Arg("personUuid") personUuid: string, @Arg("teamUuid") teamUuid: string - ): Promise { + ): Promise> { const membership = await this.membershipRepository.assignPersonToTeam({ personParam: { uuid: personUuid, @@ -318,17 +312,7 @@ export class PersonResolver { position: MembershipPositionType.Member, }); - if (membership == null) { - return GetMembershipResponse.newOk< - MembershipNode | null, - GetMembershipResponse - >(null); - } - - return GetMembershipResponse.newOk< - MembershipNode | null, - GetMembershipResponse - >(membershipModelToResource(membership)); + return membership.map(membershipModelToResource); } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) From c67fca4d462fdf7cd84138b73cf554be9c0c0b5e Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 01:31:37 +0000 Subject: [PATCH 132/153] Refactor person code to use Result type for error handling --- .../repositories/person/PersonRepository.ts | 1053 ++++++++++------- .../person/personModelToResource.ts | 31 +- .../person/personRepositoryUtils.ts | 17 +- .../server/src/resolvers/PersonResolver.ts | 219 ++-- 4 files changed, 723 insertions(+), 597 deletions(-) diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index e64fcc2a..6c17ce29 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -1,4 +1,4 @@ -import type { Committee, Membership, Person } from "@prisma/client"; +import type { Committee, Membership, Person, Team } from "@prisma/client"; import { Prisma, PrismaClient } from "@prisma/client"; import { AuthSource, @@ -13,12 +13,22 @@ import { TeamLegacyStatus, TeamType, } from "@ukdanceblue/common"; +import { Result } from "true-myth"; +import { err, ok } from "true-myth/result"; import { Service } from "typedi"; import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; +import { ActionDeniedError } from "../../lib/error/control.js"; +import { + InvalidArgumentError, + InvariantError, + NotFoundError, +} from "../../lib/error/direct.js"; +import { toBasicError } from "../../lib/error/error.js"; +import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import type { SimpleUniqueParam } from "../shared.js"; +import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; @@ -70,7 +80,7 @@ export class PersonRepository { // Finders - findPersonForLogin( + async findPersonForLogin( authIds: [Exclude, string][], userInfo: { uuid?: string | null; @@ -81,131 +91,177 @@ export class PersonRepository { }, memberOf?: (string | number)[], captainOf?: (string | number)[] - ) { - return findPersonForLogin( - this.prisma, - authIds, - userInfo, - memberOf, - captainOf - ); + ): Promise< + Result>, RepositoryError> + > { + try { + const row = await findPersonForLogin( + this.prisma, + authIds, + userInfo, + memberOf, + captainOf + ); + return ok(row); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - async findPersonByUnique(param: UniquePersonParam) { - return this.prisma.person.findUnique({ where: param }); + async findPersonByUnique( + param: UniquePersonParam + ): Promise> { + try { + const row = await this.prisma.person.findUnique({ where: param }); + if (!row) { + return err(new NotFoundError({ what: "Person" })); + } + return ok(row); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - async findPersonAndTeamsByUnique(param: UniquePersonParam) { - return this.prisma.person.findUnique({ - where: param, - include: { - memberships: { - include: { - team: true, + async findPersonAndTeamsByUnique( + param: UniquePersonParam + ): Promise< + Result< + Person & { memberships: (Membership & { team: Team })[] }, + RepositoryError + > + > { + try { + const row = await this.prisma.person.findUnique({ + where: param, + include: { + memberships: { + include: { + team: true, + }, }, }, - }, - }); + }); + if (!row) { + return err(new NotFoundError({ what: "Person" })); + } + return ok(row); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - async getDbRoleOfPerson(param: UniquePersonParam) { - const person = await this.prisma.person.findUnique({ - where: param, - select: { - linkblue: true, - memberships: { - select: { - committeeRole: true, + async getDbRoleOfPerson( + param: UniquePersonParam + ): Promise> { + try { + const person = await this.prisma.person.findUnique({ + where: param, + select: { + linkblue: true, + memberships: { + select: { + committeeRole: true, + }, }, }, - }, - }); + }); - if (!person) { - return null; - } - if (person.memberships.some((m) => m.committeeRole != null)) { - return DbRole.Committee; - } - if (person.linkblue) { - return DbRole.UKY; + if (!person) { + return ok(DbRole.None); + } + if (person.memberships.some((m) => m.committeeRole != null)) { + return ok(DbRole.Committee); + } + if (person.linkblue) { + return ok(DbRole.UKY); + } + return ok(DbRole.Public); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } - return DbRole.Public; } async getEffectiveCommitteeRolesOfPerson( param: UniquePersonParam - ): Promise { - const effectiveCommitteeRoles: EffectiveCommitteeRole[] = []; - - const committees = await this.prisma.membership.findMany({ - where: { - person: param, - team: { - correspondingCommittee: { - isNot: null, + ): Promise< + Result + > { + try { + const effectiveCommitteeRoles: EffectiveCommitteeRole[] = []; + + const committees = await this.prisma.membership.findMany({ + where: { + person: param, + team: { + correspondingCommittee: { + isNot: null, + }, + }, + committeeRole: { + not: null, }, }, - committeeRole: { - not: null, - }, - }, - select: { - team: { - select: { - correspondingCommittee: { - select: { - identifier: true, - parentCommittee: { - select: { - identifier: true, + select: { + team: { + select: { + correspondingCommittee: { + select: { + identifier: true, + parentCommittee: { + select: { + identifier: true, + }, }, - }, - childCommittees: { - select: { - identifier: true, + childCommittees: { + select: { + identifier: true, + }, }, }, }, }, }, + committeeRole: true, }, - committeeRole: true, - }, - }); + }); - for (const committee of committees) { - if (committee.team.correspondingCommittee) { - if (!committee.committeeRole) { - throw new DetailedError(ErrorCode.InternalFailure, "No role found"); - } - const role = EffectiveCommitteeRole.init( - committee.team.correspondingCommittee.identifier, - committee.committeeRole - ); - effectiveCommitteeRoles.push(role); - if (committee.team.correspondingCommittee.parentCommittee) { - const parentRole = EffectiveCommitteeRole.init( - committee.team.correspondingCommittee.parentCommittee.identifier, - CommitteeRole.Member + for (const committee of committees) { + if (committee.team.correspondingCommittee) { + if (!committee.committeeRole) { + return err( + new InvariantError("No role found for committee membership") + ); + } + const role = EffectiveCommitteeRole.init( + committee.team.correspondingCommittee.identifier, + committee.committeeRole ); - effectiveCommitteeRoles.push(parentRole); + effectiveCommitteeRoles.push(role); + if (committee.team.correspondingCommittee.parentCommittee) { + const parentRole = EffectiveCommitteeRole.init( + committee.team.correspondingCommittee.parentCommittee.identifier, + CommitteeRole.Member + ); + effectiveCommitteeRoles.push(parentRole); + } + const childRoles = + committee.team.correspondingCommittee.childCommittees.map((child) => + EffectiveCommitteeRole.init( + child.identifier, + committee.committeeRole! + ) + ); + effectiveCommitteeRoles.push(...childRoles); } - const childRoles = - committee.team.correspondingCommittee.childCommittees.map((child) => - EffectiveCommitteeRole.init( - child.identifier, - committee.committeeRole! - ) - ); - effectiveCommitteeRoles.push(...childRoles); } - } - return effectiveCommitteeRoles; + return ok(effectiveCommitteeRoles); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - listPeople({ + async listPeople({ filters, order, skip, @@ -218,73 +274,127 @@ export class PersonRepository { | null; skip?: number | undefined | null; take?: number | undefined | null; - }): Promise { - const where: Prisma.PersonWhereInput = buildPersonWhere(filters); - const orderBy: Prisma.PersonOrderByWithRelationInput = - buildPersonOrder(order); - - return this.prisma.person.findMany({ - where, - orderBy, - skip: skip ?? undefined, - take: take ?? undefined, - }); + }): Promise> { + try { + const where: Prisma.PersonWhereInput = buildPersonWhere(filters); + const orderBy = buildPersonOrder(order); + if (orderBy.isErr) { + return err(orderBy.error); + } + + const rows = await this.prisma.person.findMany({ + where, + orderBy: orderBy.value, + skip: skip ?? undefined, + take: take ?? undefined, + }); + + return ok(rows); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - countPeople({ + async countPeople({ filters, }: { filters?: readonly PersonFilters[] | undefined | null; - }): Promise { - const where: Prisma.PersonWhereInput = buildPersonWhere(filters); - - return this.prisma.person.count({ where }); - } + }): Promise> { + try { + const where: Prisma.PersonWhereInput = buildPersonWhere(filters); - searchByName(name: string): Promise { - return this.prisma.person.findMany({ - where: { - name: { - contains: name, - mode: "insensitive", - }, - }, - }); + return ok(await this.prisma.person.count({ where })); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - searchByLinkblue(linkblue: string): Promise { - return this.prisma.person.findMany({ - where: { - linkblue: { - contains: linkblue, - mode: "insensitive", - }, - }, - }); + async searchByName(name: string): Promise> { + try { + return ok( + await this.prisma.person.findMany({ + where: { + name: { + contains: name, + mode: "insensitive", + }, + }, + }) + ); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } - async findCommitteeMembershipsOfPerson(param: UniquePersonParam) { - const rows = await this.prisma.person.findUnique({ - where: param, - select: { - memberships: { + async searchByLinkblue( + linkblue: string + ): Promise> { + try { + return ok( + await this.prisma.person.findMany({ where: { - team: { - type: TeamType.Committee, + linkblue: { + contains: linkblue, + mode: "insensitive", }, }, - include: { - team: { - select: { - correspondingCommittee: true, + }) + ); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } + } + + async findCommitteeMembershipsOfPerson( + param: UniquePersonParam + ): Promise< + Result< + (Membership & { team: { correspondingCommittee: Committee } })[], + RepositoryError + > + > { + try { + const rows = await this.prisma.person.findUnique({ + where: param, + select: { + memberships: { + where: { + team: { + type: TeamType.Committee, + correspondingCommittee: { + isNot: null, + }, + }, + }, + include: { + team: { + select: { + correspondingCommittee: true, + }, }, }, }, }, - }, - }); + }); - return rows?.memberships ?? null; + if (!rows) { + return err(new NotFoundError({ what: "Person" })); + } + + return ok( + rows.memberships.filter( + ( + m + ): m is typeof m & { + team: { correspondingCommittee: Committee }; + } => { + return m.team.correspondingCommittee != null; + } + ) + ); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async findMembershipsOfPerson( @@ -299,37 +409,45 @@ export class PersonRepository { | Record = {}, types: TeamType[] | undefined = undefined, includeTeam: boolean = false - ) { - const rows = await this.prisma.person - .findUnique({ - where: param, - }) - .memberships({ - include: { - team: includeTeam, - }, - where: { - AND: [ - opts, - types - ? { - team: { - type: { - in: types, + ): Promise> { + try { + const rows = await this.prisma.person + .findUnique({ + where: param, + }) + .memberships({ + include: { + team: includeTeam, + }, + where: { + AND: [ + opts, + types + ? { + team: { + type: { + in: types, + }, }, - }, - } - : {}, - ], - }, - }); + } + : {}, + ], + }, + }); - return rows ?? null; + if (!rows) { + return err(new NotFoundError({ what: "Person" })); + } + + return ok(rows); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } // Mutators - createPerson({ + async createPerson({ name, email, linkblue, @@ -339,27 +457,35 @@ export class PersonRepository { email: string; linkblue?: string | null; authIds?: { source: Exclude; value: string }[] | null; - }): Promise { - return this.prisma.person.create({ - data: { - name, - email, - linkblue, - authIdPairs: authIds - ? { - createMany: { - data: authIds.map((authId): Prisma.AuthIdPairCreateInput => { - return { - source: authId.source, - value: authId.value, - person: { connect: { email } }, - }; - }), - }, - } - : undefined, - }, - }); + }): Promise> { + try { + return ok( + await this.prisma.person.create({ + data: { + name, + email, + linkblue, + authIdPairs: authIds + ? { + createMany: { + data: authIds.map( + (authId): Prisma.AuthIdPairCreateInput => { + return { + source: authId.source, + value: authId.value, + person: { connect: { email } }, + }; + } + ), + }, + } + : undefined, + }, + }) + ); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } async updatePerson( @@ -382,331 +508,360 @@ export class PersonRepository { memberOf?: SimpleUniqueParam[] | undefined | null; captainOf?: SimpleUniqueParam[] | undefined | null; } - ) { - let personId: number; - if ("id" in param) { - personId = param.id; - } else if ("uuid" in param) { - const found = await this.prisma.person.findUnique({ - where: { uuid: param.uuid }, - select: { id: true }, - }); - if (found == null) { - return null; + ): Promise> { + try { + let personId: number; + if ("id" in param) { + personId = param.id; + } else if ("uuid" in param) { + const found = await this.prisma.person.findUnique({ + where: { uuid: param.uuid }, + select: { id: true }, + }); + if (found == null) { + return err(new NotFoundError({ what: "Person" })); + } + personId = found.id; + } else { + return err(new InvalidArgumentError("Must provide either UUID or ID")); } - personId = found.id; - } else { - throw new Error("Must provide either UUID or ID"); - } - const [memberOfIds, captainOfIds] = await Promise.all([ - memberOf - ? Promise.all( - memberOf.map((team) => - this.prisma.team - .findUnique({ - where: team, - select: { id: true }, - }) - .then((team) => team?.id) + const [memberOfIds, captainOfIds] = await Promise.all([ + memberOf + ? Promise.all( + memberOf.map((team) => + this.prisma.team + .findUnique({ + where: team, + select: { id: true }, + }) + .then((team) => team?.id) + ) ) - ) - : Promise.resolve(null), - captainOf - ? Promise.all( - captainOf.map((team) => - this.prisma.team - .findUnique({ - where: team, - select: { id: true }, - }) - .then((team) => team?.id) + : Promise.resolve(null), + captainOf + ? Promise.all( + captainOf.map((team) => + this.prisma.team + .findUnique({ + where: team, + select: { id: true }, + }) + .then((team) => team?.id) + ) ) - ) - : Promise.resolve(null), - ]); - - try { - return await this.prisma.person.update({ - where: param, - data: { - name, - email, - linkblue, - authIdPairs: authIds - ? { - upsert: authIds.map((authId) => { - return { - create: { - source: authId.source, - value: authId.value, - }, - update: { - value: authId.value, - }, - where: { - personId_source: { - personId, + : Promise.resolve(null), + ]); + + return ok( + await this.prisma.person.update({ + where: param, + data: { + name, + email, + linkblue, + authIdPairs: authIds + ? { + upsert: authIds.map((authId) => { + return { + create: { source: authId.source, + value: authId.value, }, - }, - }; - }), - } - : undefined, - memberships: - // TODO: this nesting is nightmarish and should be refactored - memberOf || captainOf - ? { - connectOrCreate: [ - ...(memberOfIds - ?.filter( - (id): id is Exclude => id != null - ) - .map( - ( - teamId - ): Prisma.MembershipCreateOrConnectWithoutPersonInput => { - return { - where: { personId_teamId: { personId, teamId } }, - create: { - position: MembershipPositionType.Member, - team: { - connect: { - id: teamId, + update: { + value: authId.value, + }, + where: { + personId_source: { + personId, + source: authId.source, + }, + }, + }; + }), + } + : undefined, + memberships: + // How many indents is too many? This many. This many is too many + // TODO: this nesting is nightmarish and should be refactored + memberOf || captainOf + ? { + connectOrCreate: [ + ...(memberOfIds + ?.filter( + (id): id is Exclude => + id != null + ) + .map( + ( + teamId + ): Prisma.MembershipCreateOrConnectWithoutPersonInput => { + return { + where: { personId_teamId: { personId, teamId } }, + create: { + position: MembershipPositionType.Member, + team: { + connect: { + id: teamId, + }, }, }, - }, - }; - } - ) ?? []), - ...(captainOfIds - ?.filter( - (id): id is Exclude => id != null - ) - .map( - ( - teamId - ): Prisma.MembershipCreateOrConnectWithoutPersonInput => { - return { - where: { personId_teamId: { personId, teamId } }, - create: { - position: MembershipPositionType.Captain, - team: { - connect: { - id: teamId, + }; + } + ) ?? []), + ...(captainOfIds + ?.filter( + (id): id is Exclude => + id != null + ) + .map( + ( + teamId + ): Prisma.MembershipCreateOrConnectWithoutPersonInput => { + return { + where: { personId_teamId: { personId, teamId } }, + create: { + position: MembershipPositionType.Captain, + team: { + connect: { + id: teamId, + }, }, }, - }, - }; - } - ) ?? []), - ], - } - : undefined, - }, - }); + }; + } + ) ?? []), + ], + } + : undefined, + }, + }) + ); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return null; + return err(new NotFoundError({ what: "Person" })); } else { - throw error; + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); } } } - async deletePerson(identifier: UniquePersonParam): Promise { + async deletePerson( + identifier: UniquePersonParam + ): Promise> { try { - return await this.prisma.person.delete({ where: identifier }); + return ok(await this.prisma.person.delete({ where: identifier })); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return null; + return err(new NotFoundError({ what: "Person" })); } else { - throw error; + return err( + toPrismaError(error).unwrapOrElse(() => toBasicError(error)) + ); } } } - async getDemoUser() { - let demoTeam = await this.prisma.team.findFirst({ - where: { - legacyStatus: TeamLegacyStatus.DemoTeam, + async getDemoUser(): Promise< + Result< + Person & { + memberships: (Membership & { + team: Team; + })[]; }, - }); - - if (!demoTeam) { - const someMarathon = await this.prisma.marathon.findFirst({ - orderBy: { - year: "asc", + RepositoryError + > + > { + try { + let demoTeam = await this.prisma.team.findFirst({ + where: { + legacyStatus: TeamLegacyStatus.DemoTeam, }, }); - if (!someMarathon) { - throw new DetailedError( - ErrorCode.NotFound, - "No marathons found for demo user" - ); - } - - demoTeam = await this.prisma.team.create({ - data: { - name: "Demo Team", - type: "Spirit", - marathon: { - connect: someMarathon, + if (!demoTeam) { + const someMarathon = await this.prisma.marathon.findFirst({ + orderBy: { + year: "asc", }, - legacyStatus: TeamLegacyStatus.DemoTeam, - persistentIdentifier: "demo-team", - }, - }); - } + }); + + if (!someMarathon) { + return err(new NotFoundError({ what: "Marathon" })); + } - return this.prisma.person.upsert({ - where: { - authIdPairs: { - some: { - source: AuthSource.Demo, - value: "demo-user", + demoTeam = await this.prisma.team.create({ + data: { + name: "Demo Team", + type: "Spirit", + marathon: { + connect: someMarathon, + }, + legacyStatus: TeamLegacyStatus.DemoTeam, + persistentIdentifier: "demo-team", }, - }, - email: "demo-user@dancblue.org", - }, - create: { - email: "demo-user@dancblue.org", - name: "Demo User", - linkblue: "demo-user", - memberships: { - create: { - team: { - connect: { - id: demoTeam.id, + }); + } + + return ok( + await this.prisma.person.upsert({ + where: { + authIdPairs: { + some: { + source: AuthSource.Demo, + value: "demo-user", }, }, - position: MembershipPositionType.Captain, + email: "demo-user@dancblue.org", }, - }, - pointEntries: { create: { - team: { - connect: { - id: demoTeam.id, + email: "demo-user@dancblue.org", + name: "Demo User", + linkblue: "demo-user", + memberships: { + create: { + team: { + connect: { + id: demoTeam.id, + }, + }, + position: MembershipPositionType.Captain, + }, + }, + pointEntries: { + create: { + team: { + connect: { + id: demoTeam.id, + }, + }, + points: 1, + comment: "Demo point", }, }, - points: 1, - comment: "Demo point", }, - }, - }, - update: { - email: "demo-user@dancblue.org", - name: "Demo User", - linkblue: "demo-user", - }, - include: { - memberships: { + update: { + email: "demo-user@dancblue.org", + name: "Demo User", + linkblue: "demo-user", + }, include: { - team: true, + memberships: { + include: { + team: true, + }, + }, }, - }, - }, - }); + }) + ); + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + } } public async getPrimaryCommitteeOfPerson( person: UniquePersonParam, marathon?: UniqueMarathonParam - ): Promise<[Membership, Committee] | null> { - const committees = await this.prisma.membership.findMany({ - where: { - person, - team: { - marathon, - type: TeamType.Committee, + ): Promise< + Result<[Membership, Committee], RepositoryError | InvariantError> + > { + try { + const committees = await this.prisma.membership.findMany({ + where: { + person, + team: { + marathon, + type: TeamType.Committee, + }, }, - }, - include: { - team: { - include: { - correspondingCommittee: true, + include: { + team: { + include: { + correspondingCommittee: true, + }, }, }, - }, - }); - - if (committees.length === 0) { - return null; - } + }); - let bestCommittee = undefined; - let fallbackCommittee = undefined; + if (committees.length === 0) { + return err(new NotFoundError({ what: "Primary committee" })); + } - for (let i = 1; i <= committees.length; i++) { - const committee = committees[i]; - if (committee) { - // We don't want to return the overall committee or vice committee if we have a better option - if ( - committee.team.correspondingCommittee?.identifier === - CommitteeIdentifier.overallCommittee || - committee.team.correspondingCommittee?.identifier === - CommitteeIdentifier.viceCommittee - ) { - fallbackCommittee = committee; - continue; - } + let bestCommittee = undefined; + let fallbackCommittee = undefined; - if (bestCommittee) { + for (let i = 1; i <= committees.length; i++) { + const committee = committees[i]; + if (committee) { + // We don't want to return the overall committee or vice committee if we have a better option if ( - committee.committeeRole === CommitteeRole.Chair && - bestCommittee.committeeRole !== CommitteeRole.Chair + committee.team.correspondingCommittee?.identifier === + CommitteeIdentifier.overallCommittee || + committee.team.correspondingCommittee?.identifier === + CommitteeIdentifier.viceCommittee ) { - bestCommittee = committee; + fallbackCommittee = committee; continue; - } else if ( - committee.committeeRole === CommitteeRole.Coordinator && - !( - bestCommittee.committeeRole === CommitteeRole.Coordinator || - bestCommittee.committeeRole === CommitteeRole.Chair - ) - ) { + } + + if (bestCommittee) { + if ( + committee.committeeRole === CommitteeRole.Chair && + bestCommittee.committeeRole !== CommitteeRole.Chair + ) { + bestCommittee = committee; + continue; + } else if ( + committee.committeeRole === CommitteeRole.Coordinator && + !( + bestCommittee.committeeRole === CommitteeRole.Coordinator || + bestCommittee.committeeRole === CommitteeRole.Chair + ) + ) { + bestCommittee = committee; + continue; + } + } else { bestCommittee = committee; - continue; } - } else { - bestCommittee = committee; } } - } - if (bestCommittee) { - if ( - !bestCommittee.team.correspondingCommittee || - !bestCommittee.committeeRole - ) { - throw new DetailedError( - ErrorCode.InternalFailure, - "Invalid committee assignment" - ); - } - return [bestCommittee, bestCommittee.team.correspondingCommittee]; - } else if (fallbackCommittee) { - if ( - !fallbackCommittee.team.correspondingCommittee || - !fallbackCommittee.committeeRole - ) { - throw new DetailedError( - ErrorCode.InternalFailure, - "Invalid committee assignment" - ); + if (bestCommittee) { + if ( + !bestCommittee.team.correspondingCommittee || + !bestCommittee.committeeRole + ) { + return err(new InvariantError("Invalid committee assignment")); + } + return ok([bestCommittee, bestCommittee.team.correspondingCommittee]); + } else if (fallbackCommittee) { + if ( + !fallbackCommittee.team.correspondingCommittee || + !fallbackCommittee.committeeRole + ) { + throw new DetailedError( + ErrorCode.InternalFailure, + "Invalid committee assignment" + ); + } + return ok([ + fallbackCommittee, + fallbackCommittee.team.correspondingCommittee, + ]); + } else { + return err(new NotFoundError({ what: "Primary committee" })); } - return [fallbackCommittee, fallbackCommittee.team.correspondingCommittee]; - } else { - return null; + } catch (error) { + return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } } } diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index d96d19ee..aaedaac9 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -1,26 +1,31 @@ import type { Person } from "@prisma/client"; -import { DbRole, PersonNode } from "@ukdanceblue/common"; +import { PersonNode } from "@ukdanceblue/common"; +import type { Result } from "true-myth"; + +import type { RepositoryError } from "../shared.js"; import type { PersonRepository } from "./PersonRepository.js"; export async function personModelToResource( person: Person, personRepository: PersonRepository -): Promise { +): Promise> { const dbRole = await personRepository.getDbRoleOfPerson({ uuid: person.uuid, }); - return PersonNode.init({ - id: person.uuid, - name: person.name, - email: person.email, - linkblue: person.linkblue, - createdAt: person.createdAt, - updatedAt: person.updatedAt, + return dbRole.map((dbRole) => + PersonNode.init({ + id: person.uuid, + name: person.name, + email: person.email, + linkblue: person.linkblue, + createdAt: person.createdAt, + updatedAt: person.updatedAt, - // !!! Potential source of issues !!! - dbRole: dbRole ?? DbRole.None, - // !!! Potential source of issues !!! - }); + // !!! Potential source of issues !!! + dbRole, + // !!! Potential source of issues !!! + }) + ); } diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index a93e1b3a..92767f95 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -1,6 +1,9 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type Result from "true-myth/result"; +import { err, ok } from "true-myth/result"; +import { ActionDeniedError } from "../../lib/error/control.js"; import { dateFilterToPrisma, stringFilterToPrisma, @@ -13,7 +16,7 @@ export function buildPersonOrder( | readonly [key: PersonOrderKeys, sort: SortDirection][] | null | undefined -) { +): Result { const orderBy: Prisma.PersonOrderByWithRelationInput = {}; for (const [key, sort] of order ?? []) { @@ -26,12 +29,20 @@ export function buildPersonOrder( orderBy[key] = sort === SortDirection.asc ? "asc" : "desc"; break; } + case "committeeRole": + case "committeeName": + case "dbRole": default: { - throw new Error(`Unsupported sort key: ${key}`); + key satisfies "committeeRole" | "committeeName" | "dbRole"; + return err( + new ActionDeniedError( + `Unsupported filter key: ${String((key as { field?: string } | undefined)?.field)}` + ) + ); } } } - return orderBy; + return ok(orderBy); } export function buildPersonWhere( filters: readonly PersonFilters[] | null | undefined diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 6d88f8f7..30f53f12 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -5,8 +5,6 @@ import { AccessLevel, CommitteeMembershipNode, DbRole, - DetailedError, - ErrorCode, FilteredListQueryArgs, FundraisingAssignmentNode, FundraisingEntryNode, @@ -17,6 +15,7 @@ import { SortDirection, } from "@ukdanceblue/common"; import { EmailAddressResolver } from "graphql-scalars"; +import { err, ok } from "true-myth/result"; import { Arg, Args, @@ -33,7 +32,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { NotFoundError } from "../lib/error/direct.js"; +import { flipPromise } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; @@ -49,12 +48,7 @@ import { import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; -import { - AbstractGraphQLArrayOkResponse, - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { ListFundraisingEntriesArgs, ListFundraisingEntriesResponse, @@ -62,27 +56,6 @@ import { } from "./FundraisingEntryResolver.js"; import type { GraphQLContext } from "./context.js"; -@ObjectType("CreatePersonResponse", { - implements: AbstractGraphQLCreatedResponse, -}) -class CreatePersonResponse extends AbstractGraphQLCreatedResponse { - @Field(() => PersonNode) - data!: PersonNode; -} -@ObjectType("GetPersonResponse", { - implements: AbstractGraphQLOkResponse, -}) -class GetPersonResponse extends AbstractGraphQLOkResponse { - @Field(() => PersonNode, { nullable: true }) - data!: PersonNode; -} -@ObjectType("GetPeopleResponse", { - implements: AbstractGraphQLArrayOkResponse, -}) -class GetPeopleResponse extends AbstractGraphQLArrayOkResponse { - @Field(() => [PersonNode]) - data!: PersonNode[]; -} @ObjectType("ListPeopleResponse", { implements: AbstractGraphQLPaginatedResponse, }) @@ -90,10 +63,6 @@ class ListPeopleResponse extends AbstractGraphQLPaginatedResponse { @Field(() => [PersonNode]) data!: PersonNode[]; } -@ObjectType("DeletePersonResponse", { - implements: AbstractGraphQLOkResponse, -}) -class DeletePersonResponse extends AbstractGraphQLOkResponse {} @ArgsType() class ListPeopleArgs extends FilteredListQueryArgs< @@ -163,38 +132,26 @@ export class PersonResolver { ) {} @AccessControl({ accessLevel: AccessLevel.Committee }) - @Query(() => GetPersonResponse, { name: "person" }) + @Query(() => PersonNode, { name: "person" }) async getByUuid( @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId - ): Promise { + ): Promise> { const row = await this.personRepository.findPersonByUnique({ uuid: id }); - if (row == null) { - throw new CatchableConcreteError(new NotFoundError({ what: "Person" })); - } - - return GetPersonResponse.newOk( - await personModelToResource(row, this.personRepository) - ); + return row.map((row) => personModelToResource(row, this.personRepository)); } @AccessControl({ accessLevel: AccessLevel.Committee }) - @Query(() => GetPersonResponse, { name: "personByLinkBlue" }) + @Query(() => PersonNode, { name: "personByLinkBlue" }) async getByLinkBlueId( @Arg("linkBlueId") linkBlueId: string - ): Promise { + ): Promise> { const row = await this.personRepository.findPersonByUnique({ linkblue: linkBlueId, }); - if (row == null) { - return GetPersonResponse.newOk( - null - ); - } - - return GetPersonResponse.newOk( - await personModelToResource(row, this.personRepository) + return row.andThen((row) => + personModelToResource(row, this.personRepository) ); } @@ -202,7 +159,7 @@ export class PersonResolver { @Query(() => ListPeopleResponse, { name: "listPeople" }) async list( @Args(() => ListPeopleArgs) args: ListPeopleArgs - ): Promise { + ): Promise> { const [rows, total] = await Promise.all([ this.personRepository.listPeople({ filters: args.filters, @@ -220,58 +177,72 @@ export class PersonResolver { this.personRepository.countPeople({ filters: args.filters }), ]); - return ListPeopleResponse.newPaginated({ - data: await Promise.all( - rows.map((row) => personModelToResource(row, this.personRepository)) - ), - total, - page: args.page, - pageSize: args.pageSize, - }); - } + if (rows.isErr) { + return err(rows.error); + } + if (total.isErr) { + return err(total.error); + } - @Query(() => GetPersonResponse, { name: "me" }) - me(@Ctx() ctx: GraphQLContext): GetPersonResponse { - return GetPersonResponse.newOk( - ctx.authenticatedUser + return ok( + ListPeopleResponse.newPaginated({ + data: await Promise.all( + rows.value.map((row) => + personModelToResource(row, this.personRepository) + ) + ), + total: total.value, + page: args.page, + pageSize: args.pageSize, + }) ); } + @Query(() => PersonNode, { name: "me", nullable: true }) + me(@Ctx() ctx: GraphQLContext): PersonNode | null { + return ctx.authenticatedUser; + } + @AccessControl({ accessLevel: AccessLevel.Committee }) - @Query(() => GetPeopleResponse, { name: "searchPeopleByName" }) - async searchByName(@Arg("name") name: string): Promise { + @Query(() => [PersonNode], { name: "searchPeopleByName" }) + async searchByName( + @Arg("name") name: string + ): Promise> { const rows = await this.personRepository.searchByName(name); - return GetPeopleResponse.newOk( - await Promise.all( - rows.map((row) => personModelToResource(row, this.personRepository)) - ) + return flipPromise( + rows.map((rows) => { + return Promise.all( + rows.map((row) => personModelToResource(row, this.personRepository)) + ); + }) ); } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => CreatePersonResponse, { name: "createPerson" }) + @Mutation(() => PersonNode, { name: "createPerson" }) async create( @Arg("input") input: CreatePersonInput - ): Promise { + ): Promise> { const person = await this.personRepository.createPerson({ name: input.name, email: input.email, linkblue: input.linkblue, }); - return CreatePersonResponse.newCreated( - await personModelToResource(person, this.personRepository), - person.uuid + return flipPromise( + person.map((person) => + personModelToResource(person, this.personRepository) + ) ); } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => GetPersonResponse, { name: "setPerson" }) + @Mutation(() => PersonNode, { name: "setPerson" }) async set( @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId, @Arg("input") input: SetPersonInput - ): Promise { + ): Promise> { const row = await this.personRepository.updatePerson( { uuid: id, @@ -285,14 +256,8 @@ export class PersonResolver { } ); - if (row == null) { - return GetPersonResponse.newOk( - null - ); - } - - return GetPersonResponse.newOk( - await personModelToResource(row, this.personRepository) + return flipPromise( + row.map((row) => personModelToResource(row, this.personRepository)) ); } @@ -316,25 +281,27 @@ export class PersonResolver { } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) - @Mutation(() => DeletePersonResponse, { name: "deletePerson" }) + @Mutation(() => PersonNode, { name: "deletePerson" }) async delete( @Arg("uuid", () => GlobalIdScalar) { id }: GlobalId - ): Promise { + ): Promise> { const result = await this.personRepository.deletePerson({ uuid: id }); - if (result == null) { - throw new DetailedError(ErrorCode.DatabaseFailure, "Failed to delete"); - } - - auditLogger.sensitive("Person deleted", { - person: { - name: result.name, - email: result.email, - uuid: result.uuid, - }, - }); + return flipPromise( + result.map((row) => personModelToResource(row, this.personRepository)) + ).then((result) => + result.andThen((person) => { + auditLogger.sensitive("Person deleted", { + person: { + name: person.name, + email: person.email, + uuid: person.id, + }, + }); - return DeletePersonResponse.newOk(true); + return ok(person); + }) + ); } @AccessControl( @@ -351,22 +318,20 @@ export class PersonResolver { @FieldResolver(() => [CommitteeMembershipNode]) async committees( @Root() { id: { id } }: PersonNode - ): Promise { + ): Promise> { const models = await this.personRepository.findCommitteeMembershipsOfPerson( { uuid: id, } ); - if (models == null) { - return []; - } - - return models.map((row) => - committeeMembershipModelToResource( - row, - row.team.correspondingCommittee!.identifier - ) + return models.map((models) => + models.map((membership) => { + return committeeMembershipModelToResource( + membership, + membership.team.correspondingCommittee.identifier + ); + }) ); } @@ -382,7 +347,9 @@ export class PersonResolver { } ) @FieldResolver(() => [MembershipNode]) - async teams(@Root() { id: { id } }: PersonNode): Promise { + async teams( + @Root() { id: { id } }: PersonNode + ): Promise> { const models = await this.personRepository.findMembershipsOfPerson( { uuid: id, @@ -391,11 +358,7 @@ export class PersonResolver { [TeamType.Spirit] ); - if (models == null) { - return []; - } - - return models.map((row) => membershipModelToResource(row)); + return models.map((models) => models.map(membershipModelToResource)); } @AccessControl( @@ -412,7 +375,7 @@ export class PersonResolver { @FieldResolver(() => [MembershipNode]) async moraleTeams( @Root() { id: { id } }: PersonNode - ): Promise { + ): Promise> { const models = await this.personRepository.findMembershipsOfPerson( { uuid: id, @@ -421,11 +384,7 @@ export class PersonResolver { [TeamType.Morale] ); - if (models == null) { - return []; - } - - return models.map((row) => membershipModelToResource(row)); + return models.map((models) => models.map(membershipModelToResource)); } @AccessControl( @@ -442,18 +401,14 @@ export class PersonResolver { @FieldResolver(() => CommitteeMembershipNode, { nullable: true }) async primaryCommittee( @Root() { id: { id } }: PersonNode - ): Promise { + ): Promise> { const models = await this.personRepository.getPrimaryCommitteeOfPerson({ uuid: id, }); - if (models == null) { - return null; - } - - const [membership, committee] = models; - - return committeeMembershipModelToResource(membership, committee.identifier); + return models.map(([membership, committee]) => + committeeMembershipModelToResource(membership, committee.identifier) + ); } @AccessControl( From 1cedcb6a354e5a71087501351fffa4081c53a295 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 02:37:46 +0000 Subject: [PATCH 133/153] Remove true-myth and add ts-results-es --- .vscode/settings.json | 16 ++++++++-------- packages/common/package.json | 3 +-- packages/server/package.json | 2 +- yarn.lock | 17 ++++++++--------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 342b2aa1..9480439f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,16 +1,16 @@ { "eslint.workingDirectories": ["."], - "eslint.experimental.useFlatConfig": true, + "eslint.useFlatConfig": true, "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "typescript.tsserver.experimental.enableProjectDiagnostics": true, "npm.packageManager": "yarn", - "editor.formatOnSave": true, + // "editor.formatOnSave": true, "editor.tabSize": 2, - "editor.codeActionsOnSave": { - "source.organizeImports": "explicit", - "source.fixAll": "explicit" - }, + // "editor.codeActionsOnSave": { + // "source.organizeImports": "explicit", + // "source.fixAll": "explicit" + // }, "search.exclude": { "package-lock.json": true, "yarn.lock": true @@ -25,6 +25,6 @@ "Leaderboards", "Spinnable", "Whatwg" - ], - "eslint.codeActionsOnSave.mode": "problems" + ] + // "eslint.codeActionsOnSave.mode": "problems" } diff --git a/packages/common/package.json b/packages/common/package.json index 7788a0c6..3b420dec 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -74,7 +74,6 @@ }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781", "dependencies": { - "htmlparser2": "^9.1.0", - "true-myth": "^7.3.0" + "htmlparser2": "^9.1.0" } } diff --git a/packages/server/package.json b/packages/server/package.json index 57afc6e0..610e5a2a 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -61,8 +61,8 @@ "reflect-metadata": "^0.2.1", "sharp": "^0.32.1", "thumbhash": "^0.1.1", - "true-myth": "^7.3.0", "ts-node": "^10.9.1", + "ts-results-es": "^4.2.0", "type-graphql": "^2.0.0-beta.3", "typedi": "^0.10.0", "typescript": "^5.4.3", diff --git a/yarn.lock b/yarn.lock index 8de481fd..398898f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8360,7 +8360,6 @@ __metadata: "@types/validator": "npm:^13.7.17" htmlparser2: "npm:^9.1.0" jest: "npm:^29.5.0" - true-myth: "npm:^7.3.0" ts-jest: "npm:^29.1.0" ts-node: "npm:^10.9.1" typescript: "npm:^5.4.3" @@ -8631,8 +8630,8 @@ __metadata: reflect-metadata: "npm:^0.2.1" sharp: "npm:^0.32.1" thumbhash: "npm:^0.1.1" - true-myth: "npm:^7.3.0" ts-node: "npm:^10.9.1" + ts-results-es: "npm:^4.2.0" type-graphql: "npm:^2.0.0-beta.3" typedi: "npm:^0.10.0" typescript: "npm:^5.4.3" @@ -25681,13 +25680,6 @@ __metadata: languageName: node linkType: hard -"true-myth@npm:^7.3.0": - version: 7.3.0 - resolution: "true-myth@npm:7.3.0" - checksum: 10/d0c595a0dfa8fdd55dd47eae6d46d97a603b7ff3a22c1f098b2dfa5340681a533f3503e59f6e1ab3a5df7f672e889862290b5ed1a46fc4d82d7654b725d97886 - languageName: node - linkType: hard - "ts-api-utils@npm:^1.0.1": version: 1.3.0 resolution: "ts-api-utils@npm:1.3.0" @@ -25798,6 +25790,13 @@ __metadata: languageName: node linkType: hard +"ts-results-es@npm:^4.2.0": + version: 4.2.0 + resolution: "ts-results-es@npm:4.2.0" + checksum: 10/d438a09419ec621b5bf092534104df285b343866fdbb3afb91e6fd6225f48b78ea5755da055aaf4143f4aa695588e4babd71aecd0bd758b12655cf874e7b2b06 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.15.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" From 470cd54be88073a4e5647dcf7c1b873b74e65dcf Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 02:38:05 +0000 Subject: [PATCH 134/153] Switch from true-myth to ts-results-es --- .vscode/settings.json | 14 +-- eslint/base.ts | 8 +- eslint/out/base.js | 8 +- .../common/lib/api/resources/Fundraising.ts | 2 +- packages/server/src/jobs/syncDbFunds.ts | 26 ++-- packages/server/src/lib/error/direct.ts | 26 ++-- packages/server/src/lib/error/error.ts | 13 +- packages/server/src/lib/error/option.ts | 6 + packages/server/src/lib/error/prisma.ts | 22 ++-- packages/server/src/lib/error/result.ts | 2 +- .../src/lib/fundraising/DbFundsProvider.ts | 30 ++--- .../lib/fundraising/FundraisingProvider.ts | 23 +--- packages/server/src/lib/graphqlSchema.ts | 8 +- .../committee/CommitteeRepository.ts | 76 ++++++------ .../fundraising/DBFundsRepository.ts | 47 +++---- .../fundraising/FundraisingRepository.ts | 105 ++++++++-------- .../fundraisingEntryRepositoryUtils.ts | 14 +-- .../marathon/MarathonRepository.ts | 49 ++++---- .../membership/MembershipRepository.ts | 41 +++--- .../repositories/person/PersonRepository.ts | 117 +++++++++--------- .../person/personModelToResource.ts | 2 +- .../person/personRepositoryUtils.ts | 8 +- packages/server/src/repositories/shared.ts | 13 ++ .../FundraisingAssignmentResolver.ts | 27 ++-- .../src/resolvers/FundraisingEntryResolver.ts | 14 +-- .../src/resolvers/MembershipResolver.ts | 9 +- packages/server/src/resolvers/NodeResolver.ts | 25 ++-- .../server/src/resolvers/PersonResolver.ts | 24 ++-- .../src/resolvers/PointEntryResolver.ts | 9 +- packages/server/src/resolvers/TeamResolver.ts | 8 +- 30 files changed, 368 insertions(+), 408 deletions(-) create mode 100644 packages/server/src/lib/error/option.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 9480439f..e4f67123 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,12 +5,12 @@ "typescript.enablePromptUseWorkspaceTsdk": true, "typescript.tsserver.experimental.enableProjectDiagnostics": true, "npm.packageManager": "yarn", - // "editor.formatOnSave": true, + "editor.formatOnSave": true, "editor.tabSize": 2, - // "editor.codeActionsOnSave": { - // "source.organizeImports": "explicit", - // "source.fixAll": "explicit" - // }, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.fixAll": "explicit" + }, "search.exclude": { "package-lock.json": true, "yarn.lock": true @@ -25,6 +25,6 @@ "Leaderboards", "Spinnable", "Whatwg" - ] - // "eslint.codeActionsOnSave.mode": "problems" + ], + "eslint.codeActionsOnSave.mode": "problems" } diff --git a/eslint/base.ts b/eslint/base.ts index 639e068c..397a1d86 100644 --- a/eslint/base.ts +++ b/eslint/base.ts @@ -77,13 +77,7 @@ const rules: Linter.RulesRecord = { "newlines-between": "always", }, ], - "sort-imports": [ - "error", - { - allowSeparatedGroups: true, - ignoreDeclarationSort: true, - }, - ], + "sort-imports": ["off"], // Unicorn Plugin "unicorn/better-regex": "error", "unicorn/catch-error-name": "error", diff --git a/eslint/out/base.js b/eslint/out/base.js index f29be734..edd6abf5 100644 --- a/eslint/out/base.js +++ b/eslint/out/base.js @@ -75,13 +75,7 @@ const rules = { "newlines-between": "always", }, ], - "sort-imports": [ - "error", - { - allowSeparatedGroups: true, - ignoreDeclarationSort: true, - }, - ], + "sort-imports": ["off"], // Unicorn Plugin "unicorn/better-regex": "error", "unicorn/catch-error-name": "error", diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts index 05008372..480fe1dc 100644 --- a/packages/common/lib/api/resources/Fundraising.ts +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -1,7 +1,7 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; import { Maybe } from "true-myth"; -import { nothing, of } from "true-myth/maybe"; +import { nothing, of } from "ts-results-es"; import { Field, Float, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index 06f8ffb1..bd5d0677 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -1,7 +1,7 @@ import type { Marathon } from "@prisma/client"; import type { MarathonYearString } from "@ukdanceblue/common"; import Cron from "croner"; -import { Result, type Unit } from "true-myth"; +import type { Result, type None } from "ts-results-es"; import { Container } from "typedi"; import { CompositeError } from "../lib/error/composite.js"; @@ -22,7 +22,7 @@ type DoSyncError = | PrismaError | DBFundsFundraisingProviderError; async function doSync(): Promise< - Result> + Result> > { const marathonRepository = Container.get(MarathonRepository); const fundraisingRepository = Container.get(DBFundsRepository); @@ -33,20 +33,18 @@ async function doSync(): Promise< activeMarathon = await marathonRepository.findActiveMarathon(); logger.trace("Found current marathon for DBFunds sync", activeMarathon); } catch (error) { - return Result.err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return Err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); } if (!activeMarathon) { - return Result.err( + return Err( new NotFoundError({ what: "Current Marathon", where: "syncDbFunds job" }) ); } const teams = await fundraisingProvider.getTeams( activeMarathon.year as MarathonYearString ); - if (teams.isErr) { - return Result.err(teams.error); + if (teams.isErr()) { + return Err(teams.error); } logger.trace("Got teams for DBFunds sync", { teamCount: teams.value.length }); @@ -55,8 +53,8 @@ async function doSync(): Promise< activeMarathon.year as MarathonYearString, team.identifier ); - if (entries.isErr) { - return Result.err(entries.error); + if (entries.isErr()) { + return Err(entries.error); } return fundraisingRepository.overwriteTeamForFiscalYear( { @@ -76,7 +74,7 @@ async function doSync(): Promise< for (const result of results) { if (result.status === "rejected") { errors.push(toBasicError(result.reason)); - } else if (result.value.isErr) { + } else if (result.value.isErr()) { if (result.value.error instanceof CompositeError) { errors.push(...result.value.error.errors); } else { @@ -85,9 +83,7 @@ async function doSync(): Promise< } } - return errors.length > 0 - ? Result.err(new CompositeError(errors)) - : Result.ok(); + return errors.length > 0 ? Err(new CompositeError(errors)) : Ok(None); } export const syncDbFunds = new Cron( @@ -101,7 +97,7 @@ export const syncDbFunds = new Cron( async () => { logger.info("Syncing DBFunds"); const result = await doSync(); - if (result.isErr) { + if (result.isErr()) { logger.error("Failed to sync DBFunds", result.error); } else { logger.info("DBFunds sync complete"); diff --git a/packages/server/src/lib/error/direct.ts b/packages/server/src/lib/error/direct.ts index 4476ead7..acbd429e 100644 --- a/packages/server/src/lib/error/direct.ts +++ b/packages/server/src/lib/error/direct.ts @@ -1,13 +1,14 @@ -import { Maybe } from "true-myth"; +import type { Option } from "ts-results-es"; import { ConcreteError } from "./error.js"; +import { optionOf } from "./option.js"; const NotFoundErrorTag = Symbol("NotFoundError"); type NotFoundErrorTag = typeof NotFoundErrorTag; export class NotFoundError extends ConcreteError { - readonly #what: Maybe; - readonly #where: Maybe; - readonly #why: Maybe; + readonly #what: Option; + readonly #where: Option; + readonly #why: Option; readonly #sensitive: boolean; constructor({ @@ -22,9 +23,9 @@ export class NotFoundError extends ConcreteError { sensitive?: boolean; }) { super(); - this.#what = Maybe.of(what); - this.#where = Maybe.of(where); - this.#why = Maybe.of(why); + this.#what = optionOf(what); + this.#where = optionOf(where); + this.#why = optionOf(why); this.#sensitive = sensitive; } @@ -33,13 +34,10 @@ export class NotFoundError extends ConcreteError { } get detailedMessage(): string { - return `Not found: ${this.#what.unwrapOr("unknown")}${this.#where.match({ - Just: (where) => ` at ${where}`, - Nothing: () => "", - })}${this.#why.match({ - Just: (why) => ` because ${why}`, - Nothing: () => "", - })}`; + const what = this.#what.unwrapOr("unknown"); + const where = this.#where.mapOr("", (where) => ` at ${where}`); + const why = this.#why.mapOr("", (why) => ` because ${why}`); + return `Not found: ${what}${where}${why}`; } get expose(): boolean { diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index 2db2c767..5dd58aa3 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -1,5 +1,5 @@ -import type { Result } from "true-myth"; -import { err, ok } from "true-myth/result"; +import type { Result } from "ts-results-es"; +import { Err, Ok } from "ts-results-es"; export abstract class ConcreteError { abstract get message(): string; @@ -79,12 +79,3 @@ export function toBasicError(error: unknown): BasicError { return error instanceof Error ? new JsError(error) : new UnknownError(error); } -export async function flipPromise( - r: - | Result, Promise> - | Result> - | Result, E> - | Result -): Promise> { - return r.isOk ? ok(await r.value) : err(await r.error); -} diff --git a/packages/server/src/lib/error/option.ts b/packages/server/src/lib/error/option.ts new file mode 100644 index 00000000..cb66f64e --- /dev/null +++ b/packages/server/src/lib/error/option.ts @@ -0,0 +1,6 @@ +import type { Option } from "ts-results-es"; +import { None, Some } from "ts-results-es"; + +export function optionOf(value: T | null | undefined): Option { + return value == null ? None : Some(value); +} diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts index 4545c0a5..3b583365 100644 --- a/packages/server/src/lib/error/prisma.ts +++ b/packages/server/src/lib/error/prisma.ts @@ -5,8 +5,8 @@ import { PrismaClientUnknownRequestError, PrismaClientValidationError, } from "@prisma/client/runtime/library"; -import { Maybe } from "true-myth"; -import type { Just } from "true-myth/maybe"; +import type { Option } from "ts-results-es"; +import { None, Some } from "ts-results-es"; import { ConcreteError } from "./error.js"; @@ -99,23 +99,23 @@ export type SomePrismaError = | PrismaUnknownRequestError | PrismaValidationError; -export function toPrismaError(error: RawPrismaError): Just; -export function toPrismaError(error: unknown): Maybe; -export function toPrismaError(error: unknown): Maybe { +export function toPrismaError(error: RawPrismaError): Some; +export function toPrismaError(error: unknown): Option; +export function toPrismaError(error: unknown): Option { if (error instanceof PrismaClientInitializationError) { - return Maybe.of(new PrismaInitializationError(error)); + return Some(new PrismaInitializationError(error)); } if (error instanceof PrismaClientKnownRequestError) { - return Maybe.of(new PrismaKnownRequestError(error)); + return Some(new PrismaKnownRequestError(error)); } if (error instanceof PrismaClientRustPanicError) { - return Maybe.of(new PrismaRustPanicError(error)); + return Some(new PrismaRustPanicError(error)); } if (error instanceof PrismaClientUnknownRequestError) { - return Maybe.of(new PrismaUnknownRequestError(error)); + return Some(new PrismaUnknownRequestError(error)); } if (error instanceof PrismaClientValidationError) { - return Maybe.of(new PrismaValidationError(error)); + return Some(new PrismaValidationError(error)); } - return Maybe.nothing(); + return None; } diff --git a/packages/server/src/lib/error/result.ts b/packages/server/src/lib/error/result.ts index 987b1cc6..bc3a7570 100644 --- a/packages/server/src/lib/error/result.ts +++ b/packages/server/src/lib/error/result.ts @@ -1,4 +1,4 @@ -import type { Result } from "true-myth"; +import type { Result } from "ts-results-es"; import type { ConcreteError, JsError, UnknownError } from "./error.js"; import type { HttpError } from "./http.js"; diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 4d32bfe0..c44873ab 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -1,7 +1,6 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import { DateTime } from "luxon"; -import { Maybe, Result } from "true-myth"; -import { err } from "true-myth/result"; +import { Err, Ok } from "ts-results-es"; import { Inject, Service } from "typedi"; import { z } from "zod"; @@ -12,6 +11,7 @@ import { import { TimeoutError } from "../error/direct.js"; import { BasicError, toBasicError } from "../error/error.js"; import { HttpError } from "../error/http.js"; +import { optionOf } from "../error/option.js"; import { ConcreteResult } from "../error/result.js"; import { ZodError } from "../error/zod.js"; @@ -127,7 +127,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { signal: abort.signal, }); } catch (error) { - return err( + return Err( error instanceof Error && error.name === "AbortError" ? new TimeoutError("Fetching data from DbFunds") : toBasicError(error) @@ -137,10 +137,10 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { } if (!response.ok) { - return err(new HttpError(response.status)); + return Err(new HttpError(response.status)); } - return Result.ok(await response.json()); + return Ok(await response.json()); } async getTeams( @@ -151,13 +151,13 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { const calendarYear = `20${marathonYear.substring(2)}`; const path = teamTotalPath(calendarYear); const result = await this.fetchJson(path); - if (result.isErr) { - return result.cast(); + if (result.isErr()) { + return result; } const teams = dbFundsFundraisingTeamSchema.array().safeParse(result.value); if (teams.success) { - return Result.ok( + return Ok( teams.data.map((team) => ({ name: team.Team, active: team.Active, @@ -166,7 +166,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { })) ); } else { - return Result.err(new ZodError(teams.error)); + return Err(new ZodError(teams.error)); } } async getTeamEntries( @@ -179,16 +179,16 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { const path = teamEntriesPath(dbNum, calendarYear); const result = await this.fetchJson(path); - if (result.isErr) { - return result.cast(); + if (result.isErr()) { + return result; } const entries = dbFundsFundraisingEntrySchema.safeParse(result.value); if (entries.success) { - return Result.ok( + return Ok( entries.data.entries.map((entry) => ({ - donatedBy: Maybe.of(entry.donatedBy), - donatedTo: Maybe.of(entry.donatedTo), + donatedBy: optionOf(entry.donatedBy), + donatedTo: optionOf(entry.donatedTo), // donatedOn is in Eastern time donatedOn: entry.donatedOn, // Convert the amount from cents to dollars @@ -196,7 +196,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { })) ); } else { - return Result.err(new ZodError(entries.error)); + return Err(new ZodError(entries.error)); } } } diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index 571532f7..c45e81fa 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -1,10 +1,7 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; -import type { Maybe } from "true-myth"; +import type { Option } from "ts-results-es"; -import type { TimeoutError } from "../error/direct.js"; -import type { JsError, UnknownError } from "../error/error.js"; -import type { HttpError } from "../error/http.js"; import type { ConcreteResult } from "../error/result.js"; export interface FundraisingTeam { @@ -15,8 +12,8 @@ export interface FundraisingTeam { } export interface FundraisingEntry { - donatedBy: Maybe; - donatedTo: Maybe; + donatedBy: Option; + donatedTo: Option; donatedOn: DateTime; amount: number; } @@ -24,19 +21,9 @@ export interface FundraisingEntry { export interface FundraisingProvider { getTeams( marathonYear: MarathonYearString - ): Promise< - ConcreteResult< - FundraisingTeam[], - HttpError | JsError | UnknownError | TimeoutError - > - >; + ): Promise[]>>; getTeamEntries( marathonYear: MarathonYearString, identifier: unknown - ): Promise< - ConcreteResult< - FundraisingEntry[], - HttpError | JsError | UnknownError | TimeoutError - > - >; + ): Promise>; } diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index 6f23baa2..ef11ff77 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -1,6 +1,6 @@ import { fileURLToPath } from "url"; -import { isInstance } from "true-myth/result"; +import { Result } from "ts-results-es"; import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; @@ -46,8 +46,8 @@ const errorHandlingMiddleware: MiddlewareFn = async (_, next) => { throw error; } - if (isInstance(result)) { - if (result.isErr) { + if (Result.isResult(result)) { + if (result.isErr()) { logger.error("An error occurred in a resolver", result.error); throw new CatchableConcreteError( result.error instanceof ConcreteError @@ -55,7 +55,7 @@ const errorHandlingMiddleware: MiddlewareFn = async (_, next) => { : toBasicError(result.error) ); } else { - return result.value; + return result.value as unknown; } } else { return result; diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index c31c9785..4ba9fdff 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -4,19 +4,21 @@ import { CommitteeRole, SortDirection, } from "@ukdanceblue/common"; -import { Result, Unit } from "true-myth"; -import { err, ok } from "true-myth/result"; +import { Err, None, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; import { CompositeError } from "../../lib/error/composite.js"; import { InvariantError, NotFoundError } from "../../lib/error/direct.js"; import { toBasicError } from "../../lib/error/error.js"; -import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { MembershipRepository } from "../membership/MembershipRepository.js"; -import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; +import { + RepositoryError, + SimpleUniqueParam, + handleRepositoryError, +} from "../shared.js"; import * as CommitteeDescriptions from "./committeeDescriptions.js"; import { @@ -75,9 +77,9 @@ export class CommitteeRepository { skip: offset, }); - return ok(committees); + return Ok(committees); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -88,9 +90,9 @@ export class CommitteeRepository { const committee = await this.prisma.committee.findUnique({ where: param, }); - return ok(committee); + return Ok(committee); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -99,27 +101,27 @@ export class CommitteeRepository { committeeParam: CommitteeIdentifier, committeeRole: CommitteeRole, marathonParam?: UniqueMarathonParam - ): Promise>> { + ): Promise>> { try { const person = await this.prisma.person.findUnique({ where: personParam, }); if (!person) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } if (!marathonParam) { const latestMarathon = await this.marathonRepository.findActiveMarathon(); - if (latestMarathon.isErr) { - return err(latestMarathon.error); + if (latestMarathon.isErr()) { + return Err(latestMarathon.error); } marathonParam = { id: latestMarathon.value.id }; } else { const val = await this.marathonRepository.findMarathonByUnique(marathonParam); - if (val.isErr) { - return err(val.error); + if (val.isErr()) { + return Err(val.error); } } @@ -127,8 +129,8 @@ export class CommitteeRepository { forMarathon: marathonParam, }); - if (committee.isErr) { - return err(committee.error); + if (committee.isErr()) { + return Err(committee.error); } // for (const team of committee.value.correspondingTeams) { @@ -153,7 +155,7 @@ export class CommitteeRepository { for (const result of results) { if (result.status === "fulfilled") { - if (result.value.isErr) { + if (result.value.isErr()) { errors.push(result.value.error); } } else { @@ -162,33 +164,29 @@ export class CommitteeRepository { } if (errors.length > 0) { - return err(new CompositeError(errors)); + return Err(new CompositeError(errors)); } - return ok(); + return Ok(None); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } // Mutators - async deleteCommittee( - uuid: string - ): Promise> { + async deleteCommittee(uuid: string): Promise> { try { await this.prisma.committee.delete({ where: { uuid } }); - return ok(); + return Ok(None); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return ok(null); + return Err(new NotFoundError({ what: "Committee" })); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } @@ -223,9 +221,9 @@ export class CommitteeRepository { }, }); - return ok(committee); + return Ok(committee); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -243,23 +241,23 @@ export class CommitteeRepository { }); if (result?.length === 1) { - return ok(result[0]!); + return Ok(result[0]!); } else if (result?.length === 0) { - return err( + return Err( new NotFoundError({ what: "Team", where: `Committee: ${committee}, Marathon: ${JSON.stringify(marathon)}`, }) ); } else { - return err( + return Err( new InvariantError( "Multiple teams found for the given committee and marathon" ) ); } } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -273,12 +271,12 @@ export class CommitteeRepository { }) .childCommittees(); if (!childCommittees) { - return err(new NotFoundError({ what: "Committee" })); + return Err(new NotFoundError({ what: "Committee" })); } - return ok(childCommittees); + return Ok(childCommittees); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -292,9 +290,9 @@ export class CommitteeRepository { }) .parentCommittee(); - return ok(parentCommittee); + return Ok(parentCommittee); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 82d41cd0..87820a65 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,21 +1,16 @@ import { DBFundsTeam, Prisma, PrismaClient, Team } from "@prisma/client"; import { DateTime } from "luxon"; -import { Maybe, Result, Unit } from "true-myth"; -import { err, ok } from "true-myth/result"; +import { Err, None, Ok, Option, Result } from "ts-results-es"; import { Service } from "typedi"; import { CompositeError } from "../../lib/error/composite.js"; import { NotFoundError } from "../../lib/error/direct.js"; -import { BasicError, toBasicError } from "../../lib/error/error.js"; -import { - PrismaError, - SomePrismaError, - toPrismaError, -} from "../../lib/error/prisma.js"; +import { BasicError } from "../../lib/error/error.js"; +import { PrismaError, SomePrismaError } from "../../lib/error/prisma.js"; import { logger } from "../../lib/logging/standardLogging.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; -import { SimpleUniqueParam } from "../shared.js"; +import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; export type UniqueDbFundsTeamParam = | { @@ -42,14 +37,14 @@ export class DBFundsRepository { }, marathonParam: UniqueMarathonParam, dbFundsEntries: { - donatedBy: Maybe; - donatedTo: Maybe; + donatedBy: Option; + donatedTo: Option; donatedOn: DateTime; amount: number; }[] ): Promise< Result< - Unit, + None, | PrismaError | NotFoundError | CompositeError @@ -63,8 +58,8 @@ export class DBFundsRepository { } else { const marathon = await this.marathonRepository.findMarathonByUnique(marathonParam); - if (marathon.isErr) { - return marathon.cast(); + if (marathon.isErr()) { + return marathon; } marathonId = marathon.value.id; } @@ -190,11 +185,9 @@ export class DBFundsRepository { }); } - return Result.ok(); + return Ok(None); } catch (error) { - return Result.err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } @@ -215,11 +208,11 @@ export class DBFundsRepository { include: { teams: true }, }); if (!team) { - return err(new NotFoundError({ what: "Team" })); + return Err(new NotFoundError({ what: "Team" })); } - return ok(team.teams); + return Ok(team.teams); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -230,13 +223,13 @@ export class DBFundsRepository { | { dbNum: number; } - ): Promise> { + ): Promise> { try { const team = await this.prisma.team.findUnique({ where: teamParam, }); if (!team) { - return err(new NotFoundError({ what: "Team" })); + return Err(new NotFoundError({ what: "Team" })); } await this.prisma.dBFundsTeam.update({ where: @@ -257,9 +250,9 @@ export class DBFundsRepository { }, }, }); - return ok(); + return Ok(None); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -269,7 +262,7 @@ export class DBFundsRepository { onlyActive?: boolean; }): Promise> { try { - return ok( + return Ok( await this.prisma.dBFundsTeam.findMany({ where: { active: search.onlyActive ? true : undefined, @@ -284,7 +277,7 @@ export class DBFundsRepository { }) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 54d01a06..10b3d401 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -7,17 +7,16 @@ import { PrismaClient, } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; -import Maybe, { just, nothing } from "true-myth/maybe"; -import Result, { err, ok } from "true-myth/result"; +import { Err, None, Ok, Option, Result, Some } from "ts-results-es"; import { Service } from "typedi"; import { ActionDeniedError } from "../../lib/error/control.js"; import { NotFoundError } from "../../lib/error/direct.js"; -import { BasicError, toBasicError } from "../../lib/error/error.js"; -import { SomePrismaError, toPrismaError } from "../../lib/error/prisma.js"; +import { BasicError } from "../../lib/error/error.js"; +import { SomePrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { UniquePersonParam } from "../person/PersonRepository.js"; -import type { SimpleUniqueParam } from "../shared.js"; +import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; import { buildFundraisingEntryOrder, @@ -89,15 +88,15 @@ export class FundraisingEntryRepository { include: defaultInclude, }); if (!row) { - return err(new NotFoundError({ what: "FundraisingEntry" })); + return Err(new NotFoundError({ what: "FundraisingEntry" })); } - return ok( + return Ok( row as typeof row & { dbFundsEntry: NonNullable; } ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -111,11 +110,11 @@ export class FundraisingEntryRepository { where: param, }); if (!row) { - return err(new NotFoundError({ what: "FundraisingAssignment" })); + return Err(new NotFoundError({ what: "FundraisingAssignment" })); } - return ok(row); + return Ok(row); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -133,11 +132,11 @@ export class FundraisingEntryRepository { select: { assignments: true }, }); if (!entry) { - return err(new NotFoundError({ what: "FundraisingEntry" })); + return Err(new NotFoundError({ what: "FundraisingEntry" })); } - return ok(entry.assignments); + return Ok(entry.assignments); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -171,11 +170,11 @@ export class FundraisingEntryRepository { try { const whereResult = buildFundraisingEntryWhere(filters); const orderByResult = buildFundraisingEntryOrder(order); - if (whereResult.isErr) { - return err(whereResult.error); + if (whereResult.isErr()) { + return Err(whereResult.error); } - if (orderByResult.isErr) { - return err(orderByResult.error); + if (orderByResult.isErr()) { + return Err(orderByResult.error); } const where = whereResult.value; const orderBy = orderByResult.value; @@ -210,7 +209,7 @@ export class FundraisingEntryRepository { take: take ?? undefined, }); - return ok( + return Ok( rows.filter( ( row @@ -220,7 +219,7 @@ export class FundraisingEntryRepository { ) ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -233,35 +232,33 @@ export class FundraisingEntryRepository { > { try { const where = buildFundraisingEntryWhere(filters); - if (where.isErr) { - return err(where.error); + if (where.isErr()) { + return Err(where.error); } - return ok( + return Ok( await this.prisma.fundraisingEntry.count({ where: where.value }) ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } async deleteEntry( param: FundraisingEntryUniqueParam - ): Promise, SomePrismaError | BasicError>> { + ): Promise, SomePrismaError | BasicError>> { try { - return ok( - just(await this.prisma.fundraisingEntry.delete({ where: param })) + return Ok( + Some(await this.prisma.fundraisingEntry.delete({ where: param })) ); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return ok(nothing()); + return Ok(None); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } @@ -278,12 +275,12 @@ export class FundraisingEntryRepository { > { try { const entry = await this.findEntryByUnique(entryParam); - if (entry.isErr) { - return err(entry.error); + if (entry.isErr()) { + return Err(entry.error); } const assignments = await this.getAssignmentsForEntry(entryParam); - if (assignments.isErr) { - return err(assignments.error); + if (assignments.isErr()) { + return Err(assignments.error); } const totalAssigned = assignments.value.reduce( @@ -291,12 +288,12 @@ export class FundraisingEntryRepository { new Prisma.Decimal(0) ); if (entry.value.dbFundsEntry.amount.lessThan(totalAssigned.add(amount))) { - return err( + return Err( new ActionDeniedError("Total assigned amount exceeds entry amount") ); } - return ok( + return Ok( await this.prisma.fundraisingAssignment.create({ data: { amount, @@ -306,7 +303,7 @@ export class FundraisingEntryRepository { }) ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -316,13 +313,13 @@ export class FundraisingEntryRepository { Result > { try { - return ok( + return Ok( await this.prisma.fundraisingAssignment.delete({ where: assignmentParam, }) ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -346,13 +343,13 @@ export class FundraisingEntryRepository { }, }); if (!assignment) { - return err(new NotFoundError({ what: "FundraisingEntry" })); + return Err(new NotFoundError({ what: "FundraisingEntry" })); } const assignments = await this.getAssignmentsForEntry({ id: assignment.parentEntry.id, }); - if (assignments.isErr) { - return err(assignments.error); + if (assignments.isErr()) { + return Err(assignments.error); } const totalAssigned = assignments.value @@ -366,19 +363,19 @@ export class FundraisingEntryRepository { totalAssigned.add(amount) ) ) { - return err( + return Err( new ActionDeniedError("Total assigned amount exceeds entry amount") ); } - return ok( + return Ok( await this.prisma.fundraisingAssignment.update({ where: assignmentParam, data: { amount }, }) ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -391,11 +388,11 @@ export class FundraisingEntryRepository { select: { person: true }, }); if (!assignment) { - return err(new NotFoundError({ what: "FundraisingAssignment" })); + return Err(new NotFoundError({ what: "FundraisingAssignment" })); } - return ok(assignment.person); + return Ok(assignment.person); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -419,15 +416,15 @@ export class FundraisingEntryRepository { }, }); if (!assignment) { - return err(new NotFoundError({ what: "FundraisingAssignment" })); + return Err(new NotFoundError({ what: "FundraisingAssignment" })); } - return ok( + return Ok( assignment.parentEntry as typeof assignment.parentEntry & { dbFundsEntry: NonNullable; } ); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -443,9 +440,9 @@ export class FundraisingEntryRepository { const assignments = await this.prisma.fundraisingAssignment.findMany({ where: { person: personParam }, }); - return ok(assignments); + return Ok(assignments); } catch (error: unknown) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index cee2dc96..5bfecde0 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -1,7 +1,7 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; -import type { Result } from "true-myth"; -import { err, ok } from "true-myth/result"; +import type { Result } from "ts-results-es"; +import { Err, Ok } from "ts-results-es"; import { ActionDeniedError } from "../../lib/error/control.js"; import { @@ -45,11 +45,11 @@ export function buildFundraisingEntryOrder( break; } case "teamId": { - return err(new ActionDeniedError("Cannot sort by teamId")); + return Err(new ActionDeniedError("Cannot sort by teamId")); } default: { key satisfies never; - return err( + return Err( new ActionDeniedError(`Unsupported sort key: ${String(key)}`) ); } @@ -60,7 +60,7 @@ export function buildFundraisingEntryOrder( orderBy["dbFundsEntry"] = dbFundsEntryOrderBy; } - return ok(orderBy); + return Ok(orderBy); } export function buildFundraisingEntryWhere( @@ -98,7 +98,7 @@ export function buildFundraisingEntryWhere( } default: { filter satisfies never; - return err( + return Err( new ActionDeniedError( `Unsupported filter key: ${String((filter as { field?: string } | undefined)?.field)}` ) @@ -111,5 +111,5 @@ export function buildFundraisingEntryWhere( where["dbFundsEntry"] = dbFundsEntryWhere; } - return ok(where); + return Ok(where); } diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index ed9bad84..44eb0e3b 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -1,14 +1,11 @@ import { Marathon, MarathonHour, Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; -import { Result } from "true-myth"; -import { err, ok } from "true-myth/result"; +import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; import { NotFoundError } from "../../lib/error/direct.js"; -import { toBasicError } from "../../lib/error/error.js"; -import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { RepositoryError } from "../shared.js"; +import { handleRepositoryError, type RepositoryError } from "../shared.js"; import { buildMarathonOrder, @@ -70,11 +67,11 @@ export class MarathonRepository { try { const row = await this.prisma.marathon.findUnique({ where: param }); if (!row) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } - return ok(row); + return Ok(row); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -85,11 +82,11 @@ export class MarathonRepository { where: { startDate: { lte: new Date() }, endDate: { gte: new Date() } }, }); if (!marathon) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } - return ok(marathon); + return Ok(marathon); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -99,11 +96,11 @@ export class MarathonRepository { orderBy: { year: "asc" }, }); if (!marathon) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } - return ok(marathon); + return Ok(marathon); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -150,9 +147,9 @@ export class MarathonRepository { where: param, include: { hours: true }, }); - return ok(rows?.hours ?? []); + return Ok(rows?.hours ?? []); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -173,9 +170,9 @@ export class MarathonRepository { endDate, }, }); - return ok(marathon); + return Ok(marathon); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -200,17 +197,15 @@ export class MarathonRepository { endDate, }, }); - return ok(marathon); + return Ok(marathon); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } @@ -220,17 +215,15 @@ export class MarathonRepository { ): Promise> { try { const marathon = await this.prisma.marathon.delete({ where: param }); - return ok(marathon); + return Ok(marathon); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index 12d8f291..e07e5c23 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,14 +1,15 @@ import { Membership, Person, PrismaClient, Team } from "@prisma/client"; import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; -import { Result } from "true-myth"; -import { err, ok } from "true-myth/result"; +import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; import { NotFoundError } from "../../lib/error/direct.js"; -import { toBasicError } from "../../lib/error/error.js"; -import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; +import { + handleRepositoryError, + type RepositoryError, + type SimpleUniqueParam, +} from "../shared.js"; const membershipBooleanKeys = [] as const; type MembershipBooleanKey = (typeof membershipBooleanKeys)[number]; @@ -101,11 +102,11 @@ export class MembershipRepository { include, }); if (!membership) { - return err(new NotFoundError({ what: "Membership" })); + return Err(new NotFoundError({ what: "Membership" })); } - return ok(membership); + return Ok(membership); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -123,7 +124,7 @@ export class MembershipRepository { select: { id: true }, }); if (found == null) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } personId = found.id; } else { @@ -137,16 +138,16 @@ export class MembershipRepository { select: { id: true }, }); if (found == null) { - return err(new NotFoundError({ what: "Team" })); + return Err(new NotFoundError({ what: "Team" })); } teamId = found.id; } else { throw new Error("Must provide either UUID or ID"); } - return ok({ personId, teamId }); + return Ok({ personId, teamId }); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -167,8 +168,8 @@ export class MembershipRepository { )): Promise> { try { const result = await this.lookupPersonAndTeamId(personParam, teamParam); - if (result.isErr) { - return err(result.error); + if (result.isErr()) { + return Err(result.error); } const { personId, teamId } = result.value; @@ -213,9 +214,9 @@ export class MembershipRepository { update: {}, }); - return ok(membership); + return Ok(membership); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -225,8 +226,8 @@ export class MembershipRepository { ): Promise> { try { const result = await this.lookupPersonAndTeamId(personParam, teamParam); - if (result.isErr) { - return err(result.error); + if (result.isErr()) { + return Err(result.error); } const { personId, teamId } = result.value; @@ -239,9 +240,9 @@ export class MembershipRepository { }, }); - return ok(membership); + return Ok(membership); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 6c17ce29..b2b5a44c 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -13,8 +13,7 @@ import { TeamLegacyStatus, TeamType, } from "@ukdanceblue/common"; -import { Result } from "true-myth"; -import { err, ok } from "true-myth/result"; +import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; @@ -24,11 +23,13 @@ import { InvariantError, NotFoundError, } from "../../lib/error/direct.js"; -import { toBasicError } from "../../lib/error/error.js"; -import { toPrismaError } from "../../lib/error/prisma.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import type { RepositoryError, SimpleUniqueParam } from "../shared.js"; +import { + handleRepositoryError, + type RepositoryError, + type SimpleUniqueParam, +} from "../shared.js"; import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; @@ -102,9 +103,9 @@ export class PersonRepository { memberOf, captainOf ); - return ok(row); + return Ok(row); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -114,11 +115,11 @@ export class PersonRepository { try { const row = await this.prisma.person.findUnique({ where: param }); if (!row) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } - return ok(row); + return Ok(row); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -142,11 +143,11 @@ export class PersonRepository { }, }); if (!row) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } - return ok(row); + return Ok(row); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -167,17 +168,17 @@ export class PersonRepository { }); if (!person) { - return ok(DbRole.None); + return Ok(DbRole.None); } if (person.memberships.some((m) => m.committeeRole != null)) { - return ok(DbRole.Committee); + return Ok(DbRole.Committee); } if (person.linkblue) { - return ok(DbRole.UKY); + return Ok(DbRole.UKY); } - return ok(DbRole.Public); + return Ok(DbRole.Public); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -228,7 +229,7 @@ export class PersonRepository { for (const committee of committees) { if (committee.team.correspondingCommittee) { if (!committee.committeeRole) { - return err( + return Err( new InvariantError("No role found for committee membership") ); } @@ -255,9 +256,9 @@ export class PersonRepository { } } - return ok(effectiveCommitteeRoles); + return Ok(effectiveCommitteeRoles); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -278,8 +279,8 @@ export class PersonRepository { try { const where: Prisma.PersonWhereInput = buildPersonWhere(filters); const orderBy = buildPersonOrder(order); - if (orderBy.isErr) { - return err(orderBy.error); + if (orderBy.isErr()) { + return Err(orderBy.error); } const rows = await this.prisma.person.findMany({ @@ -289,9 +290,9 @@ export class PersonRepository { take: take ?? undefined, }); - return ok(rows); + return Ok(rows); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -303,15 +304,15 @@ export class PersonRepository { try { const where: Prisma.PersonWhereInput = buildPersonWhere(filters); - return ok(await this.prisma.person.count({ where })); + return Ok(await this.prisma.person.count({ where })); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } async searchByName(name: string): Promise> { try { - return ok( + return Ok( await this.prisma.person.findMany({ where: { name: { @@ -322,7 +323,7 @@ export class PersonRepository { }) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -330,7 +331,7 @@ export class PersonRepository { linkblue: string ): Promise> { try { - return ok( + return Ok( await this.prisma.person.findMany({ where: { linkblue: { @@ -341,7 +342,7 @@ export class PersonRepository { }) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -378,10 +379,10 @@ export class PersonRepository { }); if (!rows) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } - return ok( + return Ok( rows.memberships.filter( ( m @@ -393,7 +394,7 @@ export class PersonRepository { ) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -436,12 +437,12 @@ export class PersonRepository { }); if (!rows) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } - return ok(rows); + return Ok(rows); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -459,7 +460,7 @@ export class PersonRepository { authIds?: { source: Exclude; value: string }[] | null; }): Promise> { try { - return ok( + return Ok( await this.prisma.person.create({ data: { name, @@ -484,7 +485,7 @@ export class PersonRepository { }) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -519,11 +520,11 @@ export class PersonRepository { select: { id: true }, }); if (found == null) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } personId = found.id; } else { - return err(new InvalidArgumentError("Must provide either UUID or ID")); + return Err(new InvalidArgumentError("Must provide either UUID or ID")); } const [memberOfIds, captainOfIds] = await Promise.all([ @@ -553,7 +554,7 @@ export class PersonRepository { : Promise.resolve(null), ]); - return ok( + return Ok( await this.prisma.person.update({ where: param, data: { @@ -642,11 +643,9 @@ export class PersonRepository { error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } @@ -655,17 +654,15 @@ export class PersonRepository { identifier: UniquePersonParam ): Promise> { try { - return ok(await this.prisma.person.delete({ where: identifier })); + return Ok(await this.prisma.person.delete({ where: identifier })); } catch (error) { if ( error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025" ) { - return err(new NotFoundError({ what: "Person" })); + return Err(new NotFoundError({ what: "Person" })); } else { - return err( - toPrismaError(error).unwrapOrElse(() => toBasicError(error)) - ); + return handleRepositoryError(error); } } } @@ -695,7 +692,7 @@ export class PersonRepository { }); if (!someMarathon) { - return err(new NotFoundError({ what: "Marathon" })); + return Err(new NotFoundError({ what: "Marathon" })); } demoTeam = await this.prisma.team.create({ @@ -711,7 +708,7 @@ export class PersonRepository { }); } - return ok( + return Ok( await this.prisma.person.upsert({ where: { authIdPairs: { @@ -763,7 +760,7 @@ export class PersonRepository { }) ); } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } @@ -792,7 +789,7 @@ export class PersonRepository { }); if (committees.length === 0) { - return err(new NotFoundError({ what: "Primary committee" })); + return Err(new NotFoundError({ what: "Primary committee" })); } let bestCommittee = undefined; @@ -840,9 +837,9 @@ export class PersonRepository { !bestCommittee.team.correspondingCommittee || !bestCommittee.committeeRole ) { - return err(new InvariantError("Invalid committee assignment")); + return Err(new InvariantError("Invalid committee assignment")); } - return ok([bestCommittee, bestCommittee.team.correspondingCommittee]); + return Ok([bestCommittee, bestCommittee.team.correspondingCommittee]); } else if (fallbackCommittee) { if ( !fallbackCommittee.team.correspondingCommittee || @@ -853,15 +850,15 @@ export class PersonRepository { "Invalid committee assignment" ); } - return ok([ + return Ok([ fallbackCommittee, fallbackCommittee.team.correspondingCommittee, ]); } else { - return err(new NotFoundError({ what: "Primary committee" })); + return Err(new NotFoundError({ what: "Primary committee" })); } } catch (error) { - return err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); + return handleRepositoryError(error); } } } diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index aaedaac9..e5d5cae6 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -1,6 +1,6 @@ import type { Person } from "@prisma/client"; import { PersonNode } from "@ukdanceblue/common"; -import type { Result } from "true-myth"; +import type { Result } from "ts-results-es"; import type { RepositoryError } from "../shared.js"; diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index 92767f95..c64444fa 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -1,7 +1,7 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; -import type Result from "true-myth/result"; -import { err, ok } from "true-myth/result"; +import type { Result } from "ts-results-es"; +import { Err, Ok } from "ts-results-es"; import { ActionDeniedError } from "../../lib/error/control.js"; import { @@ -34,7 +34,7 @@ export function buildPersonOrder( case "dbRole": default: { key satisfies "committeeRole" | "committeeName" | "dbRole"; - return err( + return Err( new ActionDeniedError( `Unsupported filter key: ${String((key as { field?: string } | undefined)?.field)}` ) @@ -42,7 +42,7 @@ export function buildPersonOrder( } } } - return ok(orderBy); + return Ok(orderBy); } export function buildPersonWhere( filters: readonly PersonFilters[] | null | undefined diff --git a/packages/server/src/repositories/shared.ts b/packages/server/src/repositories/shared.ts index 58d801b0..4170f0d1 100644 --- a/packages/server/src/repositories/shared.ts +++ b/packages/server/src/repositories/shared.ts @@ -1,6 +1,19 @@ +import { Err } from "ts-results-es"; + import type { NotFoundError } from "../lib/error/direct.js"; import type { BasicError } from "../lib/error/error.js"; +import { toBasicError } from "../lib/error/error.js"; import type { SomePrismaError } from "../lib/error/prisma.js"; +import { toPrismaError } from "../lib/error/prisma.js"; export type SimpleUniqueParam = { id: number } | { uuid: string }; export type RepositoryError = SomePrismaError | BasicError | NotFoundError; + +export function handleRepositoryError( + error: unknown +): Err { + const prismaError = toPrismaError(error); + return prismaError.isSome() + ? Err(prismaError.unwrap()) + : Err(toBasicError(error)); +} diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index e7b053d6..21c9e426 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -10,7 +10,6 @@ import { MembershipPositionType, PersonNode, } from "@ukdanceblue/common"; -import { map } from "true-myth/result"; import { Arg, Field, @@ -23,7 +22,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { flipPromise } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; @@ -72,7 +70,8 @@ export class FundraisingAssignmentResolver { uuid: id, }); - return flipPromise(map(fundraisingAssignmentModelToNode, assignment)); + return assignment.toAsyncResult().map(fundraisingAssignmentModelToNode) + .promise; } @AccessControl(fundraisingAccess) @@ -121,13 +120,12 @@ export class FundraisingAssignmentResolver { @AccessControl(globalFundraisingAccessParam, { custom: async (_, { teamMemberships }, { id: { id } }) => { const personRepository = Container.get(PersonRepository); - const memberships = - (await personRepository.findMembershipsOfPerson( - { uuid: id }, - undefined, - undefined, - true - )) ?? []; + const memberships = await personRepository.findMembershipsOfPerson( + { uuid: id }, + undefined, + undefined, + true + ); const userCaptaincies = teamMemberships.filter( (membership) => membership.position === MembershipPositionType.Captain ); @@ -151,13 +149,14 @@ export class FundraisingAssignmentResolver { }) async person( @Root() { id: { id } }: FundraisingAssignmentNode - ): Promise>> { + ): Promise> { const person = await this.fundraisingEntryRepository.getPersonForAssignment( { uuid: id } ); - return person.map((person) => - personModelToResource(person, this.personRepository) - ); + return person + .toAsyncResult() + .andThen((person) => personModelToResource(person, this.personRepository)) + .promise; } @FieldResolver(() => FundraisingEntryNode) diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index b19ed3c2..7fbe61d0 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -11,7 +11,6 @@ import { MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; -import { map } from "true-myth/result"; import { Arg, Args, @@ -25,7 +24,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { flipPromise } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; @@ -102,7 +100,7 @@ export class FundraisingEntryResolver { const entry = await this.fundraisingEntryRepository.findEntryByUnique({ uuid: id, }); - return flipPromise(map(fundraisingEntryModelToNode, entry)); + return entry.toAsyncResult().map(fundraisingEntryModelToNode).promise; } @AccessControl(globalFundraisingAccessParam) @@ -127,10 +125,10 @@ export class FundraisingEntryResolver { filters: args.filters, }); - if (entries.isErr) { + if (entries.isErr()) { throw new CatchableConcreteError(entries.error); } - if (count.isErr) { + if (count.isErr()) { throw new CatchableConcreteError(count.error); } @@ -171,14 +169,14 @@ export class FundraisingEntryResolver { const entry = await fundraisingEntryRepository.findEntryByUnique({ uuid: id, }); - if (entry.isErr) { + if (entry.isErr()) { return false; } const dbFundsRepository = Container.get(DBFundsRepository); const teams = await dbFundsRepository.getTeamsForDbFundsTeam({ id: entry.value.dbFundsEntry.dbFundsTeamId, }); - if (teams.isErr) { + if (teams.isErr()) { return false; } return captainOf.some(({ teamId }) => @@ -195,7 +193,7 @@ export class FundraisingEntryResolver { await this.fundraisingEntryRepository.getAssignmentsForEntry({ uuid: id, }); - if (assignments.isErr) { + if (assignments.isErr()) { throw new CatchableConcreteError(assignments.error); } return Promise.all( diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 9368e2b1..5c7930a7 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -2,7 +2,6 @@ import { MembershipNode, PersonNode, TeamNode } from "@ukdanceblue/common"; import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; -import { flipPromise } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; @@ -27,9 +26,11 @@ export class MembershipResolver { } ); - return flipPromise( - row.map((row) => personModelToResource(row.person, this.personRepository)) - ); + return row + .toAsyncResult() + .andThen((row) => + personModelToResource(row.person, this.personRepository) + ).promise; } @FieldResolver(() => TeamNode) diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 040506de..00230300 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -16,7 +16,7 @@ import { PointOpportunityNode, TeamNode, } from "@ukdanceblue/common"; -import { ok } from "true-myth/result"; +import { Ok } from "ts-results-es"; import { Arg, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; @@ -64,20 +64,20 @@ export class NodeResolver { switch (id.typename) { case ConfigurationNode.constructor.name: { const { data } = await this.configurationResolver.getByUuid(id); - return ok(data); + return Ok(data); } case DeviceNode.constructor.name: { const { data } = await this.deviceResolver.getByUuid(id); - return ok(data); + return Ok(data); } case EventNode.constructor.name: { const { data } = await this.eventResolver.getByUuid(id); - return ok(data); + return Ok(data); } // TODO: fix this // case FeedResolver.constructor.name: { // const { data } = await this.feedResolver.getByUuid(id); - // return ok(data); + // return Ok(data); // } case FundraisingAssignmentNode.constructor.name: { return this.fundraisingAssignmentResolver.fundraisingAssignment(id); @@ -87,34 +87,33 @@ export class NodeResolver { } case ImageNode.constructor.name: { const { data } = await this.imageResolver.getByUuid(id); - return ok(data); + return Ok(data); } case MarathonHourNode.constructor.name: { const data = await this.marathonHourResolver.marathonHour(id); - return ok(data); + return Ok(data); } case MarathonNode.constructor.name: { return this.marathonResolver.marathon(id); } case NotificationNode.constructor.name: { const { data } = await this.notificationResolver.getByUuid(id); - return ok(data); + return Ok(data); } case PersonNode.constructor.name: { - const { data } = await this.personResolver.getByUuid(id); - return ok(data); + return this.personResolver.getByUuid(id); } case PointOpportunityNode.constructor.name: { const { data } = await this.pointOpportunityResolver.getByUuid(id); - return ok(data); + return Ok(data); } case PointEntryNode.constructor.name: { const { data } = await this.pointEntryResolver.getByUuid(id); - return ok(data); + return Ok(data); } case TeamNode.constructor.name: { const { data } = await this.teamResolver.getByUuid(id); - return ok(data); + return Ok(data); } default: { throw new Error(`Unknown typename: ${id.typename}`); diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 30f53f12..833120d5 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -15,7 +15,7 @@ import { SortDirection, } from "@ukdanceblue/common"; import { EmailAddressResolver } from "graphql-scalars"; -import { err, ok } from "true-myth/result"; +import { Err, Ok } from "ts-results-es"; import { Arg, Args, @@ -177,14 +177,14 @@ export class PersonResolver { this.personRepository.countPeople({ filters: args.filters }), ]); - if (rows.isErr) { - return err(rows.error); + if (rows.isErr()) { + return Err(rows.error); } - if (total.isErr) { - return err(total.error); + if (total.isErr()) { + return Err(total.error); } - return ok( + return Ok( ListPeopleResponse.newPaginated({ data: await Promise.all( rows.value.map((row) => @@ -299,7 +299,7 @@ export class PersonResolver { }, }); - return ok(person); + return Ok(person); }) ); } @@ -438,14 +438,14 @@ export class PersonResolver { const entry = await fundraisingEntryRepository.findEntryByUnique({ uuid: id, }); - if (entry.isErr) { + if (entry.isErr()) { return false; } const dbFundsRepository = Container.get(DBFundsRepository); const teams = await dbFundsRepository.getTeamsForDbFundsTeam({ id: entry.value.dbFundsEntry.dbFundsTeamId, }); - if (teams.isErr) { + if (teams.isErr()) { return false; } return captainOf.some(({ teamId }) => @@ -482,10 +482,10 @@ export class PersonResolver { filters: args.filters, }); - if (entries.isErr) { + if (entries.isErr()) { throw new CatchableConcreteError(entries.error); } - if (count.isErr) { + if (count.isErr()) { throw new CatchableConcreteError(count.error); } @@ -519,7 +519,7 @@ export class PersonResolver { uuid: id, }); - if (models.isErr) { + if (models.isErr()) { throw new CatchableConcreteError(models.error); } diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 569ec760..a343efde 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -10,6 +10,7 @@ import { SortDirection, TeamNode, } from "@ukdanceblue/common"; +import { Err } from "ts-results-es"; import { Arg, Args, @@ -26,6 +27,8 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { NotFoundError } from "../lib/error/direct.js"; +import { ConcreteResult } from "../lib/error/result.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; import { PointEntryRepository } from "../repositories/pointEntry/PointEntryRepository.js"; @@ -181,12 +184,14 @@ export class PointEntryResolver { @FieldResolver(() => PersonNode, { nullable: true }) async personFrom( @Root() { id: { id } }: PointEntryNode - ): Promise { + ): Promise> { const model = await this.pointEntryRepository.getPointEntryPersonFrom({ uuid: id, }); - return model ? personModelToResource(model, this.personRepository) : null; + return model + ? personModelToResource(model, this.personRepository) + : Err(new NotFoundError({ what: "Person" })); } @FieldResolver(() => TeamNode) diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 8f537ae4..41d9d1dd 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -437,10 +437,10 @@ export class TeamResolver { filters: args.filters, }); - if (entries.isErr) { + if (entries.isErr()) { throw new CatchableConcreteError(entries.error); } - if (count.isErr) { + if (count.isErr()) { throw new CatchableConcreteError(count.error); } @@ -474,7 +474,7 @@ export class TeamResolver { onlyActive: true, }); - if (rows.isErr) { + if (rows.isErr()) { throw new CatchableConcreteError(rows.error); } @@ -497,7 +497,7 @@ export class TeamResolver { { dbNum: dbFundsTeamId } ); - if (result.isErr) { + if (result.isErr()) { throw new CatchableConcreteError(result.error); } From c0170dd559cd349b0df3c5cc53a112908bb2fde6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 03:24:11 +0000 Subject: [PATCH 135/153] Fix some result issues --- packages/server/src/jobs/syncDbFunds.ts | 28 +--- .../server/src/lib/auth/findPersonForLogin.ts | 2 +- packages/server/src/lib/error/error.ts | 4 - .../repositories/device/DeviceRepository.ts | 28 ++-- .../person/personModelToResource.ts | 16 +- .../server/src/resolvers/DeviceResolver.ts | 10 +- .../server/src/resolvers/PersonResolver.ts | 104 ++++++------ .../src/resolvers/PointEntryResolver.ts | 2 +- packages/server/src/resolvers/context.ts | 156 +++++++++++------- packages/server/src/routes/api/auth/demo.ts | 8 +- .../src/routes/api/auth/oidcCallback.ts | 38 +++-- packages/server/src/seed.ts | 6 +- 12 files changed, 239 insertions(+), 163 deletions(-) diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index bd5d0677..6d7483eb 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -1,14 +1,12 @@ -import type { Marathon } from "@prisma/client"; import type { MarathonYearString } from "@ukdanceblue/common"; import Cron from "croner"; -import type { Result, type None } from "ts-results-es"; +import { Err, None, Ok, type Result } from "ts-results-es"; import { Container } from "typedi"; import { CompositeError } from "../lib/error/composite.js"; -import { NotFoundError } from "../lib/error/direct.js"; +import type { NotFoundError } from "../lib/error/direct.js"; import { toBasicError } from "../lib/error/error.js"; import type { PrismaError } from "../lib/error/prisma.js"; -import { toPrismaError } from "../lib/error/prisma.js"; import { DBFundsFundraisingProvider, type DBFundsFundraisingProviderError, @@ -27,21 +25,13 @@ async function doSync(): Promise< const marathonRepository = Container.get(MarathonRepository); const fundraisingRepository = Container.get(DBFundsRepository); const fundraisingProvider = Container.get(DBFundsFundraisingProvider); - let activeMarathon: Marathon | null = null; - try { - logger.trace("Finding current marathon for DBFunds sync"); - activeMarathon = await marathonRepository.findActiveMarathon(); - logger.trace("Found current marathon for DBFunds sync", activeMarathon); - } catch (error) { - return Err(toPrismaError(error).unwrapOrElse(() => toBasicError(error))); - } - if (!activeMarathon) { - return Err( - new NotFoundError({ what: "Current Marathon", where: "syncDbFunds job" }) - ); + const activeMarathon = await marathonRepository.findActiveMarathon(); + logger.trace("Found current marathon for DBFunds sync", activeMarathon); + if (activeMarathon.isErr()) { + return activeMarathon; } const teams = await fundraisingProvider.getTeams( - activeMarathon.year as MarathonYearString + activeMarathon.value.year as MarathonYearString ); if (teams.isErr()) { return Err(teams.error); @@ -50,7 +40,7 @@ async function doSync(): Promise< const promises = teams.value.map(async (team) => { const entries = await fundraisingProvider.getTeamEntries( - activeMarathon.year as MarathonYearString, + activeMarathon.value.year as MarathonYearString, team.identifier ); if (entries.isErr()) { @@ -63,7 +53,7 @@ async function doSync(): Promise< name: team.name, total: team.total, }, - { id: activeMarathon.id }, + { id: activeMarathon.value.id }, entries.value ); }); diff --git a/packages/server/src/lib/auth/findPersonForLogin.ts b/packages/server/src/lib/auth/findPersonForLogin.ts index d0a503fd..e203a0c8 100644 --- a/packages/server/src/lib/auth/findPersonForLogin.ts +++ b/packages/server/src/lib/auth/findPersonForLogin.ts @@ -175,5 +175,5 @@ export async function findPersonForLogin( created = true; } - return [currentPerson, created] as const; + return { currentPerson, created } as const; } diff --git a/packages/server/src/lib/error/error.ts b/packages/server/src/lib/error/error.ts index 5dd58aa3..968025ed 100644 --- a/packages/server/src/lib/error/error.ts +++ b/packages/server/src/lib/error/error.ts @@ -1,6 +1,3 @@ -import type { Result } from "ts-results-es"; -import { Err, Ok } from "ts-results-es"; - export abstract class ConcreteError { abstract get message(): string; get detailedMessage(): string { @@ -78,4 +75,3 @@ export type BasicError = JsError | UnknownError; export function toBasicError(error: unknown): BasicError { return error instanceof Error ? new JsError(error) : new UnknownError(error); } - diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index d28763f7..adc2d609 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -1,11 +1,15 @@ import type { Person } from "@prisma/client"; import { PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; +import { Err, Result } from "ts-results-es"; import { Service } from "typedi"; +import { NotFoundError } from "../../lib/error/direct.js"; +import { CatchableConcreteError } from "../../lib/formatError.js"; import type { NotificationAudience } from "../../lib/notification/NotificationProvider.js"; import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { PersonRepository } from "../person/PersonRepository.js"; +import { RepositoryError } from "../shared.js"; import { buildDeviceOrder, buildDeviceWhere } from "./deviceRepositoryUtils.js"; @@ -37,14 +41,16 @@ export class DeviceRepository { }); } - async getLastLoggedInUser(deviceUuid: string) { + async getLastLoggedInUser( + deviceUuid: string + ): Promise> { const device = await this.getDeviceByUuid(deviceUuid); - - return device?.lastSeenPersonId == null - ? null - : this.personRepository.findPersonByUnique({ - id: device.lastSeenPersonId, - }); + if (device?.lastSeenPersonId == null) { + return Err(new NotFoundError({ what: "Person" })); + } + return this.personRepository.findPersonByUnique({ + id: device.lastSeenPersonId, + }); } async listDevices({ @@ -100,11 +106,13 @@ export class DeviceRepository { let user: Person | null = null; if (lastUserId != null) { - user = await this.personRepository.findPersonByUnique({ + const userResult = await this.personRepository.findPersonByUnique({ uuid: lastUserId, }); - if (user == null) { - throw new Error("Last user not found"); + if (userResult.isErr()) { + throw new CatchableConcreteError(userResult.error); + } else { + user = userResult.value; } } diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index e5d5cae6..413724d0 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -1,20 +1,20 @@ import type { Person } from "@prisma/client"; import { PersonNode } from "@ukdanceblue/common"; -import type { Result } from "ts-results-es"; +import { AsyncResult } from "ts-results-es"; import type { RepositoryError } from "../shared.js"; import type { PersonRepository } from "./PersonRepository.js"; -export async function personModelToResource( +export function personModelToResource( person: Person, personRepository: PersonRepository -): Promise> { - const dbRole = await personRepository.getDbRoleOfPerson({ - uuid: person.uuid, - }); - - return dbRole.map((dbRole) => +): AsyncResult { + return new AsyncResult( + personRepository.getDbRoleOfPerson({ + uuid: person.uuid, + }) + ).map((dbRole) => PersonNode.init({ id: person.uuid, name: person.name, diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 7fec3b70..8eb902ce 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -25,6 +25,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { ConcreteResult } from "../lib/error/result.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; import { DeviceRepository } from "../repositories/device/DeviceRepository.js"; import { deviceModelToResource } from "../repositories/device/deviceModelToResource.js"; @@ -197,12 +198,13 @@ export class DeviceResolver { @FieldResolver(() => PersonNode, { nullable: true }) async lastLoggedInUser( @Root() { id: { id } }: DeviceNode - ): Promise { + ): Promise> { const user = await this.deviceRepository.getLastLoggedInUser(id); - return user == null - ? null - : personModelToResource(user, this.personRepository); + return user + .toAsyncResult() + .andThen((person) => personModelToResource(person, this.personRepository)) + .promise; } @FieldResolver(() => [NotificationDeliveryNode]) diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 833120d5..3162d438 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -15,7 +15,7 @@ import { SortDirection, } from "@ukdanceblue/common"; import { EmailAddressResolver } from "graphql-scalars"; -import { Err, Ok } from "ts-results-es"; +import { Ok, Result } from "ts-results-es"; import { Arg, Args, @@ -32,7 +32,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { flipPromise } from "../lib/error/error.js"; +import { ConcreteError } from "../lib/error/error.js"; import { ConcreteResult } from "../lib/error/result.js"; import { CatchableConcreteError } from "../lib/formatError.js"; import { auditLogger } from "../lib/logging/auditLogging.js"; @@ -138,7 +138,10 @@ export class PersonResolver { ): Promise> { const row = await this.personRepository.findPersonByUnique({ uuid: id }); - return row.map((row) => personModelToResource(row, this.personRepository)); + return row + .toAsyncResult() + .andThen((row) => personModelToResource(row, this.personRepository)) + .promise; } @AccessControl({ accessLevel: AccessLevel.Committee }) @@ -150,9 +153,10 @@ export class PersonResolver { linkblue: linkBlueId, }); - return row.andThen((row) => - personModelToResource(row, this.personRepository) - ); + return row + .toAsyncResult() + .andThen((row) => personModelToResource(row, this.personRepository)) + .promise; } @AccessControl({ accessLevel: AccessLevel.Committee }) @@ -177,25 +181,30 @@ export class PersonResolver { this.personRepository.countPeople({ filters: args.filters }), ]); - if (rows.isErr()) { - return Err(rows.error); - } - if (total.isErr()) { - return Err(total.error); - } - - return Ok( - ListPeopleResponse.newPaginated({ - data: await Promise.all( - rows.value.map((row) => - personModelToResource(row, this.personRepository) + return Result.all([ + await rows + .toAsyncResult() + .andThen(async (rows) => + Result.all( + await Promise.all( + rows.map( + (row) => + personModelToResource(row, this.personRepository).promise + ) + ) ) - ), - total: total.value, - page: args.page, - pageSize: args.pageSize, - }) - ); + ).promise, + total, + ]).andThen(([rows, total]) => { + return Ok( + ListPeopleResponse.newPaginated({ + data: rows, + total, + page: args.page, + pageSize: args.pageSize, + }) + ); + }); } @Query(() => PersonNode, { name: "me", nullable: true }) @@ -210,13 +219,17 @@ export class PersonResolver { ): Promise> { const rows = await this.personRepository.searchByName(name); - return flipPromise( - rows.map((rows) => { - return Promise.all( - rows.map((row) => personModelToResource(row, this.personRepository)) - ); - }) - ); + return rows + .toAsyncResult() + .andThen(async (rows) => + Result.all( + await Promise.all( + rows.map( + (row) => personModelToResource(row, this.personRepository).promise + ) + ) + ) + ).promise; } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @@ -230,11 +243,10 @@ export class PersonResolver { linkblue: input.linkblue, }); - return flipPromise( - person.map((person) => - personModelToResource(person, this.personRepository) - ) - ); + return person + .toAsyncResult() + .andThen((person) => personModelToResource(person, this.personRepository)) + .promise; } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @@ -256,9 +268,10 @@ export class PersonResolver { } ); - return flipPromise( - row.map((row) => personModelToResource(row, this.personRepository)) - ); + return row + .toAsyncResult() + .andThen((row) => personModelToResource(row, this.personRepository)) + .promise; } @AccessControl({ accessLevel: AccessLevel.CommitteeChairOrCoordinator }) @@ -287,10 +300,10 @@ export class PersonResolver { ): Promise> { const result = await this.personRepository.deletePerson({ uuid: id }); - return flipPromise( - result.map((row) => personModelToResource(row, this.personRepository)) - ).then((result) => - result.andThen((person) => { + return result + .toAsyncResult() + .andThen((row) => personModelToResource(row, this.personRepository)) + .map((person) => { auditLogger.sensitive("Person deleted", { person: { name: person.name, @@ -299,9 +312,8 @@ export class PersonResolver { }, }); - return Ok(person); - }) - ); + return person; + }).promise; } @AccessControl( diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index a343efde..09aa3b25 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -190,7 +190,7 @@ export class PointEntryResolver { }); return model - ? personModelToResource(model, this.personRepository) + ? personModelToResource(model, this.personRepository).promise : Err(new NotFoundError({ what: "Person" })); } diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 122bc6f5..21880c4d 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -13,9 +13,12 @@ import { roleToAccessLevel, } from "@ukdanceblue/common"; import type { DefaultState } from "koa"; +import { Ok } from "ts-results-es"; import { Container } from "typedi"; import { defaultAuthorization, parseUserJwt } from "../lib/auth/index.js"; +import { NotFoundError } from "../lib/error/direct.js"; +import type { ConcreteResult } from "../lib/error/result.js"; import { logger } from "../lib/logging/logger.js"; import { PersonRepository } from "../repositories/person/PersonRepository.js"; import { personModelToResource } from "../repositories/person/personModelToResource.js"; @@ -37,71 +40,94 @@ function isSuperAdmin(committeeRoles: EffectiveCommitteeRole[]): boolean { async function withUserInfo( inputContext: GraphQLContext, userId: string -): Promise { +): Promise> { const outputContext = structuredClone(inputContext); const personRepository = Container.get(PersonRepository); const person = await personRepository.findPersonAndTeamsByUnique({ uuid: userId, }); + if (person.isErr()) { + if (person.error.tag === NotFoundError.Tag) { + // Short-circuit if the user is not found + return Ok(outputContext); + } + return person; + } + // If we found a user, set the authenticated user - if (person) { - // Convert the user to a resource and set it on the context - const personResource = await personModelToResource( - person, - personRepository - ); - logger.trace("graphqlContextFunction Found user", personResource); - outputContext.authenticatedUser = personResource; - outputContext.userData.userId = userId; - - // Set the committees the user is on - const committeeRoles = - await personRepository.getEffectiveCommitteeRolesOfPerson({ - id: person.id, - }); - const committees = committeeRoles; - logger.trace("graphqlContextFunction Found committees", ...committees); - outputContext.authorization.committees = committees; - - // Set the teams the user is on - const teamMemberships = - (await personRepository.findMembershipsOfPerson( - { - id: person.id, - }, - {}, - undefined, - true - )) ?? []; - logger.trace( - "graphqlContextFunction Found team memberships", - ...teamMemberships - ); - outputContext.teamMemberships = teamMemberships.map((membership) => ({ - teamType: membership.team.type, - position: membership.position, - teamId: membership.team.uuid, - })); - - // Set the effective committee roles the user has - const effectiveCommitteeRoles = - await personRepository.getEffectiveCommitteeRolesOfPerson({ - id: person.id, - }); - logger.trace( - "graphqlContextFunction Effective committee roles", - ...effectiveCommitteeRoles - ); - outputContext.authorization.committees = effectiveCommitteeRoles; + // Convert the user to a resource and set it on the context + const personResource = await personModelToResource( + person.value, + personRepository + ).promise; + if (personResource.isErr()) { + return personResource; + } + logger.trace("graphqlContextFunction Found user", personResource.value); + outputContext.authenticatedUser = personResource.value; + outputContext.userData.userId = userId; + + // Set the committees the user is on + const committeeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ + id: person.value.id, + }); + if (committeeRoles.isErr()) { + return committeeRoles; + } + logger.trace( + "graphqlContextFunction Found committees", + ...committeeRoles.value + ); + outputContext.authorization.committees = committeeRoles.value; - // If the user is on a committee, override the dbRole - if (effectiveCommitteeRoles.length > 0) { - outputContext.authorization.dbRole = DbRole.Committee; + // Set the teams the user is on + let teamMemberships = await personRepository.findMembershipsOfPerson( + { + id: person.value.id, + }, + {}, + undefined, + true + ); + if (teamMemberships.isErr()) { + if (teamMemberships.error.tag === NotFoundError.Tag) { + teamMemberships = Ok([]); + } else { + return teamMemberships; } } + logger.trace( + "graphqlContextFunction Found team memberships", + ...teamMemberships.value + ); + outputContext.teamMemberships = teamMemberships.value.map((membership) => ({ + teamType: membership.team.type, + position: membership.position, + teamId: membership.team.uuid, + })); + + // Set the effective committee roles the user has + const effectiveCommitteeRoles = + await personRepository.getEffectiveCommitteeRolesOfPerson({ + id: person.value.id, + }); + if (effectiveCommitteeRoles.isErr()) { + return effectiveCommitteeRoles; + } + logger.trace( + "graphqlContextFunction Effective committee roles", + ...effectiveCommitteeRoles.value + ); + outputContext.authorization.committees = effectiveCommitteeRoles.value; - return outputContext; + // If the user is on a committee, override the dbRole + if (effectiveCommitteeRoles.value.length > 0) { + outputContext.authorization.dbRole = DbRole.Committee; + } + + return Ok(outputContext); } const defaultContext: Readonly = Object.freeze({ @@ -160,7 +186,14 @@ export const graphqlContextFunction: ContextFunction< }, userId ); - let superAdmin = isSuperAdmin(contextWithUser.authorization.committees); + if (contextWithUser.isErr()) { + logger.error( + "graphqlContextFunction Error looking up user", + contextWithUser.error + ); + return structuredClone(defaultContext); + } + let superAdmin = isSuperAdmin(contextWithUser.value.authorization.committees); if ( superAdmin && ctx.request.headers["x-ukdb-masquerade"] && @@ -177,16 +210,23 @@ export const graphqlContextFunction: ContextFunction< }, ctx.request.headers["x-ukdb-masquerade"] ); + if (contextWithUser.isErr()) { + logger.error( + "graphqlContextFunction Error looking up user", + contextWithUser.error + ); + return structuredClone(defaultContext); + } superAdmin = false; } const finalContext: GraphQLContext = { - ...contextWithUser, + ...contextWithUser.value, authorization: { - ...contextWithUser.authorization, + ...contextWithUser.value.authorization, accessLevel: superAdmin ? AccessLevel.SuperAdmin - : roleToAccessLevel(contextWithUser.authorization), + : roleToAccessLevel(contextWithUser.value.authorization), }, }; diff --git a/packages/server/src/routes/api/auth/demo.ts b/packages/server/src/routes/api/auth/demo.ts index 82d99e94..9cb1244a 100644 --- a/packages/server/src/routes/api/auth/demo.ts +++ b/packages/server/src/routes/api/auth/demo.ts @@ -28,9 +28,15 @@ export const demoLogin = async (ctx: Context) => { } const person = await getOrMakeDemoUser(); + if (person.isErr()) { + return ctx.throw( + person.error.expose ? person.error.message : "Error creating demo user", + 500 + ); + } const jwt = makeUserJwt({ - userId: person.uuid, + userId: person.value.uuid, authSource: AuthSource.Demo, }); if (setCookie) { diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index dc6558ea..362e27ba 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -1,7 +1,6 @@ import type { IncomingMessage } from "node:http"; import { AuthSource, makeUserData } from "@ukdanceblue/common"; -import createHttpError from "http-errors"; import jsonwebtoken from "jsonwebtoken"; import type { Context } from "koa"; import { DateTime } from "luxon"; @@ -38,7 +37,7 @@ export const oidcCallback = async (ctx: Context) => { uuid: flowSessionId, }); if (!session?.codeVerifier) { - throw new createHttpError.InternalServerError( + throw new Error( `No ${session == null ? "session" : "codeVerifier"} found` ); } @@ -54,14 +53,14 @@ export const oidcCallback = async (ctx: Context) => { }); sessionDeleted = true; if (!tokenSet.access_token) { - throw new createHttpError.InternalServerError("Missing access token"); + throw new Error("Missing access token"); } const { oid: objectId, email } = tokenSet.claims(); const decodedJwt = jsonwebtoken.decode(tokenSet.access_token, { json: true, }); if (!decodedJwt) { - throw new createHttpError.InternalServerError("Error decoding JWT"); + throw new Error("Error decoding JWT"); } const { given_name: firstName, @@ -78,11 +77,21 @@ export const oidcCallback = async (ctx: Context) => { if (typeof objectId !== "string") { return ctx.throw("Missing OID", 500); } - const [currentPerson] = await personRepository.findPersonForLogin( + const findPersonForLoginResult = await personRepository.findPersonForLogin( [[AuthSource.LinkBlue, objectId]], { email, linkblue } ); + if (findPersonForLoginResult.isErr()) { + return ctx.throw( + findPersonForLoginResult.error.expose + ? findPersonForLoginResult.error.message + : "Error finding person", + 500 + ); + } + const { currentPerson } = findPersonForLoginResult.value; + if ( !currentPerson.authIdPairs.some( ({ source, value }) => @@ -124,15 +133,24 @@ export const oidcCallback = async (ctx: Context) => { } ); - if (!updatedPerson) { + if (updatedPerson.isErr()) { return ctx.throw("Failed to update database entry", 500); } + const personNode = await personModelToResource( + updatedPerson.value, + personRepository + ).promise; + if (personNode.isErr()) { + return ctx.throw( + personNode.error.expose + ? personNode.error.message + : "Error creating person node", + 500 + ); + } const jwt = makeUserJwt( - makeUserData( - await personModelToResource(updatedPerson, personRepository), - AuthSource.LinkBlue - ) + makeUserData(personNode.value, AuthSource.LinkBlue) ); let redirectTo = session.redirectToAfterLogin; if (session.sendToken) { diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index 4cbc41da..5be2ba3b 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -37,11 +37,15 @@ try { ) ); + if (techPeople.some((p) => p.isErr())) { + throw new Error("Failed to create all tech committee people"); + } + await Promise.all( techPeople.flatMap((person) => committeeRepository.assignPersonToCommittee( { - id: person.id, + id: person.unwrap().id, }, CommitteeIdentifier.techCommittee, CommitteeRole.Coordinator From dbc3a7c81d0ce52b9dacb0d345afdc2545a6fb85 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 03:50:36 +0000 Subject: [PATCH 136/153] Misc --- .../common/lib/api/resources/Fundraising.ts | 27 ++++++------ packages/common/package.json | 3 +- packages/server/.env.example | 1 + schema.graphql | 41 ++++--------------- yarn.lock | 1 + 5 files changed, 25 insertions(+), 48 deletions(-) diff --git a/packages/common/lib/api/resources/Fundraising.ts b/packages/common/lib/api/resources/Fundraising.ts index 480fe1dc..80c0c93d 100644 --- a/packages/common/lib/api/resources/Fundraising.ts +++ b/packages/common/lib/api/resources/Fundraising.ts @@ -1,7 +1,6 @@ import { DateTimeISOResolver } from "graphql-scalars"; import type { DateTime } from "luxon"; -import { Maybe } from "true-myth"; -import { nothing, of } from "ts-results-es"; +import { None, Option, Some } from "ts-results-es"; import { Field, Float, ObjectType } from "type-graphql"; import { dateTimeFromSomething } from "../../utility/time/intervalTools.js"; @@ -19,18 +18,18 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { id!: GlobalId; @Field(() => String, { nullable: true, name: "donatedByText" }) private _donatedByText!: string | null; - get donatedByText(): Maybe { - return of(this._donatedByText); + get donatedByText(): Option { + return this._donatedByText ? Some(this._donatedByText) : None; } - set donatedByText(value: Maybe) { + set donatedByText(value: Option) { this._donatedByText = value.unwrapOr(null); } @Field(() => String, { nullable: true, name: "donatedToText" }) private _donatedToText!: string | null; - get donatedToText(): Maybe { - return of(this._donatedToText); + get donatedToText(): Option { + return this._donatedToText ? Some(this._donatedToText) : None; } - set donatedToText(value: Maybe) { + set donatedToText(value: Option) { this._donatedToText = value.unwrapOr(null); } @Field(() => DateTimeISOResolver) @@ -47,8 +46,8 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { public static init(init: { id: string; - donatedByText: Maybe | string | null; - donatedToText: Maybe | string | null; + donatedByText: Option | string | null; + donatedToText: Option | string | null; donatedOn: Date; amount: number; createdAt: Date; @@ -61,15 +60,15 @@ export class FundraisingEntryNode extends TimestampedResource implements Node { }; node.donatedByText = init.donatedByText == null - ? nothing() + ? None : typeof init.donatedByText === "string" - ? of(init.donatedByText) + ? Some(init.donatedByText) : init.donatedByText; node.donatedToText = init.donatedToText == null - ? nothing() + ? None : typeof init.donatedToText === "string" - ? of(init.donatedToText) + ? Some(init.donatedToText) : init.donatedToText; node.donatedOn = init.donatedOn; node.amount = init.amount; diff --git a/packages/common/package.json b/packages/common/package.json index 3b420dec..69824675 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -74,6 +74,7 @@ }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781", "dependencies": { - "htmlparser2": "^9.1.0" + "htmlparser2": "^9.1.0", + "ts-results-es": "^4.2.0" } } diff --git a/packages/server/.env.example b/packages/server/.env.example index 884397d7..a287a58a 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -9,6 +9,7 @@ NODE_ENV=development APPLICATION_HOST=localhost APPLICATION_PORT=8000 MS_OIDC_URL= +LOG_DIR="logs" # These values must always be set manually: COOKIE_SECRET= diff --git a/schema.graphql b/schema.graphql index 3765b6ff..4d11e122 100644 --- a/schema.graphql +++ b/schema.graphql @@ -176,12 +176,6 @@ input CreatePersonInput { name: String } -type CreatePersonResponse implements AbstractGraphQLCreatedResponse & AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PersonNode! - ok: Boolean! - uuid: String! -} - input CreatePointEntryInput { comment: String opportunityUuid: String @@ -261,10 +255,6 @@ type DeleteNotificationResponse implements AbstractGraphQLOkResponse & GraphQLBa ok: Boolean! } -type DeletePersonResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - ok: Boolean! -} - type DeletePointEntryResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { ok: Boolean! } @@ -613,26 +603,11 @@ type GetImageByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseRe ok: Boolean! } -type GetMembershipResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: MembershipNode - ok: Boolean! -} - type GetNotificationByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { data: NotificationNode! ok: Boolean! } -type GetPeopleResponse implements AbstractGraphQLArrayOkResponse & GraphQLBaseResponse { - data: [PersonNode!]! - ok: Boolean! -} - -type GetPersonResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { - data: PersonNode - ok: Boolean! -} - type GetPointEntryByUuidResponse implements AbstractGraphQLOkResponse & GraphQLBaseResponse { data: PointEntryNode! ok: Boolean! @@ -1006,7 +981,7 @@ type Mutation { acknowledgeDeliveryIssue(uuid: GlobalId!): AcknowledgeDeliveryIssueResponse! addExistingImageToEvent(eventId: String!, imageId: String!): AddEventImageResponse! addMap(imageUuid: String!, uuid: GlobalId!): MarathonHourNode! - addPersonToTeam(personUuid: String!, teamUuid: String!): GetMembershipResponse! + addPersonToTeam(personUuid: String!, teamUuid: String!): MembershipNode! assignEntryToPerson(entryId: String!, input: AssignEntryToPersonInput!, personId: String!): FundraisingAssignmentNode! assignTeamToDbFundsTeam(dbFundsTeamId: Float!, teamId: String!): Void! attachImageToFeedItem(feedItemUuid: String!, imageUuid: String!): FeedNode! @@ -1017,7 +992,7 @@ type Mutation { createImage(input: CreateImageInput!): ImageNode! createMarathon(input: CreateMarathonInput!): MarathonNode! createMarathonHour(input: CreateMarathonHourInput!, marathonUuid: String!): MarathonHourNode! - createPerson(input: CreatePersonInput!): CreatePersonResponse! + createPerson(input: CreatePersonInput!): PersonNode! createPointEntry(input: CreatePointEntryInput!): CreatePointEntryResponse! createPointOpportunity(input: CreatePointOpportunityInput!): CreatePointOpportunityResponse! createTeam(input: CreateTeamInput!, marathon: String!): CreateTeamResponse! @@ -1036,7 +1011,7 @@ type Mutation { force: Boolean uuid: GlobalId! ): DeleteNotificationResponse! - deletePerson(uuid: GlobalId!): DeletePersonResponse! + deletePerson(uuid: GlobalId!): PersonNode! deletePointEntry(uuid: GlobalId!): DeletePointEntryResponse! deletePointOpportunity(uuid: GlobalId!): DeletePointOpportunityResponse! deleteTeam(uuid: GlobalId!): DeleteTeamResponse! @@ -1054,7 +1029,7 @@ type Mutation { setImageUrl(uuid: GlobalId!): ImageNode! setMarathon(input: SetMarathonInput!, uuid: GlobalId!): MarathonNode! setMarathonHour(input: SetMarathonHourInput!, uuid: GlobalId!): MarathonHourNode! - setPerson(input: SetPersonInput!, uuid: GlobalId!): GetPersonResponse! + setPerson(input: SetPersonInput!, uuid: GlobalId!): PersonNode! setPointOpportunity(input: SetPointOpportunityInput!, uuid: GlobalId!): SinglePointOpportunityResponse! setTeam(input: SetTeamInput!, uuid: GlobalId!): SingleTeamResponse! stageNotification(audience: NotificationAudienceInput!, body: String!, title: String!, url: String): StageNotificationResponse! @@ -1768,7 +1743,7 @@ type Query { """The string filters to apply to the query""" stringFilters: Void ): ListMarathonsResponse! - me: GetPersonResponse! + me: PersonNode node(id: GlobalId!): Node! notification(uuid: GlobalId!): GetNotificationByUuidResponse! notificationDeliveries( @@ -1858,8 +1833,8 @@ type Query { """The string filters to apply to the query""" stringFilters: [NotificationResolverKeyedStringFilterItem!] ): ListNotificationsResponse! - person(uuid: GlobalId!): GetPersonResponse! - personByLinkBlue(linkBlueId: String!): GetPersonResponse! + person(uuid: GlobalId!): PersonNode! + personByLinkBlue(linkBlueId: String!): PersonNode! pointEntries( """The boolean filters to apply to the query""" booleanFilters: Void @@ -1948,7 +1923,7 @@ type Query { stringFilters: [PointOpportunityResolverKeyedStringFilterItem!] ): ListPointOpportunitiesResponse! pointOpportunity(uuid: GlobalId!): SinglePointOpportunityResponse! - searchPeopleByName(name: String!): GetPeopleResponse! + searchPeopleByName(name: String!): [PersonNode!]! team(uuid: GlobalId!): SingleTeamResponse! teams( """The boolean filters to apply to the query""" diff --git a/yarn.lock b/yarn.lock index 398898f6..a61ce48e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8362,6 +8362,7 @@ __metadata: jest: "npm:^29.5.0" ts-jest: "npm:^29.1.0" ts-node: "npm:^10.9.1" + ts-results-es: "npm:^4.2.0" typescript: "npm:^5.4.3" vitest: "npm:^1.4.0" peerDependencies: From 3390e9495639b20944e210f02700b76a7d35e3a6 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 03:58:04 +0000 Subject: [PATCH 137/153] Fix graphql errors --- .../common/lib/graphql-client-admin/gql.ts | 40 ++++---- .../lib/graphql-client-admin/graphql.ts | 98 +++++++------------ .../common/lib/graphql-client-public/gql.ts | 20 ++-- .../lib/graphql-client-public/graphql.ts | 78 +++++---------- .../src/common/hooks/useTabBarConfig.ts | 4 +- .../common/marathonComponents/TriviaCrack.tsx | 14 ++- packages/mobile/src/context/auth.tsx | 4 +- .../mobile/src/navigation/root/RootScreen.tsx | 6 +- .../root/tab/spirit/SpiritStack.tsx | 12 +-- .../src/elements/components/PersonSearch.tsx | 30 +++--- .../forms/person/create/PersonCreator.tsx | 4 +- .../forms/person/create/PersonCreatorGQL.ts | 3 +- .../forms/person/edit/PersonEditorGQL.ts | 2 +- .../create/PointEntryCreatorGQL.ts | 22 ++--- .../create/PointEntryPersonLookup.tsx | 32 +++--- .../viewers/person/PersonDeletePopup.tsx | 8 +- .../edit-person/EditPersonPage.tsx | 6 +- .../view-person/ViewPersonPage.tsx | 6 +- 18 files changed, 152 insertions(+), 237 deletions(-) diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-admin/gql.ts index 6c72fe43..3edfdcde 100644 --- a/packages/common/lib/graphql-client-admin/gql.ts +++ b/packages/common/lib/graphql-client-admin/gql.ts @@ -16,7 +16,7 @@ const documents = { "\n query ActiveMarathon {\n latestMarathon {\n id\n year\n startDate\n endDate\n }\n marathons(sendAll: true) {\n data {\n id\n year\n }\n }\n }\n": types.ActiveMarathonDocument, "\n query SelectedMarathon($marathonId: GlobalId!) {\n marathon(uuid: $marathonId) {\n id\n year\n startDate\n endDate\n }\n }\n": types.SelectedMarathonDocument, "\n query ImagePicker($stringFilters: [ImageResolverKeyedStringFilterItem!]) {\n images(stringFilters: $stringFilters, pageSize: 9) {\n data {\n id\n alt\n url\n }\n }\n }\n": types.ImagePickerDocument, - "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.PersonSearchDocument, + "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n id\n name\n linkblue\n }\n personByLinkBlue(linkBlueId: $search) {\n id\n name\n linkblue\n }\n }\n": types.PersonSearchDocument, "\n fragment SingleNotificationFragment on NotificationNode {\n id\n title\n body\n deliveryIssue\n deliveryIssueAcknowledgedAt\n sendAt\n startedSendingAt\n createdAt\n deliveryCount\n deliveryIssueCount {\n DeviceNotRegistered\n InvalidCredentials\n MessageRateExceeded\n MessageTooBig\n MismatchSenderId\n Unknown\n }\n }\n": types.SingleNotificationFragmentFragmentDoc, "\n mutation CreateNotification(\n $title: String!\n $body: String!\n $audience: NotificationAudienceInput!\n $url: String\n ) {\n stageNotification(\n title: $title\n body: $body\n audience: $audience\n url: $url\n ) {\n uuid\n }\n }\n": types.CreateNotificationDocument, "\n mutation CancelNotificationSchedule($uuid: GlobalId!) {\n abortScheduledNotification(uuid: $uuid) {\n ok\n }\n }\n": types.CancelNotificationScheduleDocument, @@ -24,14 +24,14 @@ const documents = { "\n mutation SendNotification($uuid: GlobalId!) {\n sendNotification(uuid: $uuid) {\n ok\n }\n }\n": types.SendNotificationDocument, "\n mutation ScheduleNotification($uuid: GlobalId!, $sendAt: DateTimeISO!) {\n scheduleNotification(uuid: $uuid, sendAt: $sendAt) {\n ok\n }\n }\n": types.ScheduleNotificationDocument, "\n fragment TeamNameFragment on TeamNode {\n id\n name\n }\n": types.TeamNameFragmentFragmentDoc, - "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n ok\n uuid\n }\n }\n": types.PersonCreatorDocument, + "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n id\n }\n }\n": types.PersonCreatorDocument, "\n fragment PersonEditorFragment on PersonNode {\n id\n name\n linkblue\n email\n teams {\n position\n team {\n id\n name\n }\n }\n }\n": types.PersonEditorFragmentFragmentDoc, - "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n": types.PersonEditorDocument, + "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n id\n }\n }\n": types.PersonEditorDocument, "\n mutation CreatePointEntry($input: CreatePointEntryInput!) {\n createPointEntry(input: $input) {\n data {\n id\n }\n }\n }\n": types.CreatePointEntryDocument, - "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n": types.GetPersonByUuidDocument, - "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n": types.GetPersonByLinkBlueDocument, - "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n": types.SearchPersonByNameDocument, - "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n uuid\n }\n }\n": types.CreatePersonByLinkBlueDocument, + "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n id\n name\n linkblue\n }\n }\n": types.GetPersonByUuidDocument, + "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n id\n name\n }\n }\n": types.GetPersonByLinkBlueDocument, + "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n id\n name\n }\n }\n": types.SearchPersonByNameDocument, + "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n id\n }\n }\n": types.CreatePersonByLinkBlueDocument, "\n query PointEntryOpportunityLookup($name: String!) {\n pointOpportunities(\n stringFilters: { field: name, comparison: SUBSTRING, value: $name }\n sendAll: true\n ) {\n data {\n name\n id\n }\n }\n }\n": types.PointEntryOpportunityLookupDocument, "\n mutation CreatePointOpportunity($input: CreatePointOpportunityInput!) {\n createPointOpportunity(input: $input) {\n uuid\n }\n }\n": types.CreatePointOpportunityDocument, "\n mutation TeamCreator($input: CreateTeamInput!, $marathonUuid: String!) {\n createTeam(input: $input, marathon: $marathonUuid) {\n ok\n uuid\n }\n }\n": types.TeamCreatorDocument, @@ -47,7 +47,7 @@ const documents = { "\n query NotificationsTableQuery(\n $page: Int\n $pageSize: Int\n $sortBy: [String!]\n $sortDirection: [SortDirection!]\n $dateFilters: [NotificationResolverKeyedDateFilterItem!]\n $isNullFilters: [NotificationResolverKeyedIsNullFilterItem!]\n $oneOfFilters: [NotificationResolverKeyedOneOfFilterItem!]\n $stringFilters: [NotificationResolverKeyedStringFilterItem!]\n ) {\n notifications(\n page: $page\n pageSize: $pageSize\n sortBy: $sortBy\n sortDirection: $sortDirection\n dateFilters: $dateFilters\n isNullFilters: $isNullFilters\n oneOfFilters: $oneOfFilters\n stringFilters: $stringFilters\n ) {\n page\n pageSize\n total\n data {\n ...NotificationsTableFragment\n }\n }\n }\n": types.NotificationsTableQueryDocument, "\n mutation DeletePointEntry($uuid: GlobalId!) {\n deletePointEntry(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePointEntryDocument, "\n fragment PointEntryTableFragment on PointEntryNode {\n id\n personFrom {\n name\n linkblue\n }\n points\n pointOpportunity {\n name\n opportunityDate\n }\n comment\n }\n": types.PointEntryTableFragmentFragmentDoc, - "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n": types.DeletePersonDocument, + "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n id\n }\n }\n": types.DeletePersonDocument, "\n fragment PersonViewerFragment on PersonNode {\n id\n name\n linkblue\n email\n dbRole\n teams {\n position\n team {\n id\n name\n }\n }\n committees {\n identifier\n role\n }\n }\n": types.PersonViewerFragmentFragmentDoc, "\n mutation DeleteTeam($uuid: GlobalId!) {\n deleteTeam(uuid: $uuid) {\n ok\n }\n }\n": types.DeleteTeamDocument, "\n fragment TeamViewerFragment on TeamNode {\n id\n name\n marathon {\n id\n year\n }\n legacyStatus\n totalPoints\n type\n members {\n person {\n id\n name\n linkblue\n }\n position\n }\n }\n": types.TeamViewerFragmentFragmentDoc, @@ -83,8 +83,8 @@ const documents = { "\n query NotificationManager($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationManagerDocument, "\n query NotificationViewer($uuid: GlobalId!) {\n notification(uuid: $uuid) {\n data {\n ...SingleNotificationFragment\n }\n }\n }\n": types.NotificationViewerDocument, "\n query CreatePersonPage {\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.CreatePersonPageDocument, - "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, - "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n": types.ViewPersonPageDocument, + "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonEditorFragment\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n": types.EditPersonPageDocument, + "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonViewerFragment\n }\n }\n": types.ViewPersonPageDocument, "\n query EditTeamPage($uuid: GlobalId!) {\n team(uuid: $uuid) {\n data {\n ...TeamEditorFragment\n }\n }\n }\n": types.EditTeamPageDocument, "\n query ViewTeamFundraisingDocument($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n # TODO: Add filtering and pagination\n fundraisingEntries(sendAll: true) {\n data {\n id\n amount\n donatedByText\n donatedToText\n donatedOn\n assignments {\n id\n amount\n person {\n name\n }\n }\n }\n }\n }\n }\n }\n": types.ViewTeamFundraisingDocumentDocument, "\n query ViewTeamPage($teamUuid: GlobalId!) {\n team(uuid: $teamUuid) {\n data {\n ...TeamViewerFragment\n pointEntries {\n ...PointEntryTableFragment\n }\n }\n }\n }\n": types.ViewTeamPageDocument, @@ -119,7 +119,7 @@ export function graphql(source: "\n query ImagePicker($stringFilters: [ImageRes /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n data {\n id\n name\n linkblue\n }\n }\n personByLinkBlue(linkBlueId: $search) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n id\n name\n linkblue\n }\n personByLinkBlue(linkBlueId: $search) {\n id\n name\n linkblue\n }\n }\n"): (typeof documents)["\n query PersonSearch($search: String!) {\n searchPeopleByName(name: $search) {\n id\n name\n linkblue\n }\n personByLinkBlue(linkBlueId: $search) {\n id\n name\n linkblue\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -151,7 +151,7 @@ export function graphql(source: "\n fragment TeamNameFragment on TeamNode {\n /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n ok\n uuid\n }\n }\n"): (typeof documents)["\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n ok\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation PersonCreator($input: CreatePersonInput!) {\n createPerson(input: $input) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -159,7 +159,7 @@ export function graphql(source: "\n fragment PersonEditorFragment on PersonNode /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"): (typeof documents)["\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n id\n }\n }\n"): (typeof documents)["\n mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) {\n setPerson(uuid: $uuid, input: $input) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -167,19 +167,19 @@ export function graphql(source: "\n mutation CreatePointEntry($input: CreatePoi /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n id\n name\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n id\n name\n linkblue\n }\n }\n"): (typeof documents)["\n query GetPersonByUuid($uuid: GlobalId!) {\n person(uuid: $uuid) {\n id\n name\n linkblue\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n data {\n id\n name\n }\n }\n }\n"]; +export function graphql(source: "\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n id\n name\n }\n }\n"): (typeof documents)["\n query GetPersonByLinkBlue($linkBlue: String!) {\n personByLinkBlue(linkBlueId: $linkBlue) {\n id\n name\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n data {\n id\n name\n }\n }\n }\n"]; +export function graphql(source: "\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n id\n name\n }\n }\n"): (typeof documents)["\n query SearchPersonByName($name: String!) {\n searchPeopleByName(name: $name) {\n id\n name\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n uuid\n }\n }\n"): (typeof documents)["\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n uuid\n }\n }\n"]; +export function graphql(source: "\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n id\n }\n }\n"): (typeof documents)["\n mutation CreatePersonByLinkBlue(\n $linkBlue: String!\n $email: EmailAddress!\n $teamUuid: String!\n ) {\n createPerson(\n input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] }\n ) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -243,7 +243,7 @@ export function graphql(source: "\n fragment PointEntryTableFragment on PointEn /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"): (typeof documents)["\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n ok\n }\n }\n"]; +export function graphql(source: "\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n id\n }\n }\n"): (typeof documents)["\n mutation DeletePerson($uuid: GlobalId!) {\n deletePerson(uuid: $uuid) {\n id\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -387,11 +387,11 @@ export function graphql(source: "\n query CreatePersonPage {\n teams(sendAll /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonEditorFragment\n }\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonEditorFragment\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"): (typeof documents)["\n query EditPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonEditorFragment\n }\n teams(sendAll: true, sortBy: [\"name\"], sortDirection: [asc]) {\n data {\n ...TeamNameFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"): (typeof documents)["\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n data {\n ...PersonViewerFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonViewerFragment\n }\n }\n"): (typeof documents)["\n query ViewPersonPage($uuid: GlobalId!) {\n person(uuid: $uuid) {\n ...PersonViewerFragment\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-admin/graphql.ts index e9ddf71d..5469e760 100644 --- a/packages/common/lib/graphql-client-admin/graphql.ts +++ b/packages/common/lib/graphql-client-admin/graphql.ts @@ -212,13 +212,6 @@ export type CreatePersonInput = { readonly name?: InputMaybe; }; -export type CreatePersonResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'CreatePersonResponse'; - readonly data: PersonNode; - readonly ok: Scalars['Boolean']['output']; - readonly uuid: Scalars['String']['output']; -}; - export type CreatePointEntryInput = { readonly comment?: InputMaybe; readonly opportunityUuid?: InputMaybe; @@ -296,11 +289,6 @@ export type DeleteNotificationResponse = AbstractGraphQlOkResponse & GraphQlBase readonly ok: Scalars['Boolean']['output']; }; -export type DeletePersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'DeletePersonResponse'; - readonly ok: Scalars['Boolean']['output']; -}; - export type DeletePointEntryResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'DeletePointEntryResponse'; readonly ok: Scalars['Boolean']['output']; @@ -620,30 +608,12 @@ export type GetImageByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResp readonly ok: Scalars['Boolean']['output']; }; -export type GetMembershipResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetMembershipResponse'; - readonly data?: Maybe; - readonly ok: Scalars['Boolean']['output']; -}; - export type GetNotificationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetNotificationByUuidResponse'; readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; }; -export type GetPeopleResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetPeopleResponse'; - readonly data: ReadonlyArray; - readonly ok: Scalars['Boolean']['output']; -}; - -export type GetPersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetPersonResponse'; - readonly data?: Maybe; - readonly ok: Scalars['Boolean']['output']; -}; - export type GetPointEntryByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPointEntryByUuidResponse'; readonly data: PointEntryNode; @@ -977,7 +947,7 @@ export type Mutation = { readonly acknowledgeDeliveryIssue: AcknowledgeDeliveryIssueResponse; readonly addExistingImageToEvent: AddEventImageResponse; readonly addMap: MarathonHourNode; - readonly addPersonToTeam: GetMembershipResponse; + readonly addPersonToTeam: MembershipNode; readonly assignEntryToPerson: FundraisingAssignmentNode; readonly assignTeamToDbFundsTeam: Scalars['Void']['output']; readonly attachImageToFeedItem: FeedNode; @@ -988,7 +958,7 @@ export type Mutation = { readonly createImage: ImageNode; readonly createMarathon: MarathonNode; readonly createMarathonHour: MarathonHourNode; - readonly createPerson: CreatePersonResponse; + readonly createPerson: PersonNode; readonly createPointEntry: CreatePointEntryResponse; readonly createPointOpportunity: CreatePointOpportunityResponse; readonly createTeam: CreateTeamResponse; @@ -1001,7 +971,7 @@ export type Mutation = { readonly deleteMarathon: Scalars['Void']['output']; readonly deleteMarathonHour: Scalars['Void']['output']; readonly deleteNotification: DeleteNotificationResponse; - readonly deletePerson: DeletePersonResponse; + readonly deletePerson: PersonNode; readonly deletePointEntry: DeletePointEntryResponse; readonly deletePointOpportunity: DeletePointOpportunityResponse; readonly deleteTeam: DeleteTeamResponse; @@ -1018,7 +988,7 @@ export type Mutation = { readonly setImageUrl: ImageNode; readonly setMarathon: MarathonNode; readonly setMarathonHour: MarathonHourNode; - readonly setPerson: GetPersonResponse; + readonly setPerson: PersonNode; readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; readonly stageNotification: StageNotificationResponse; @@ -1672,18 +1642,18 @@ export type Query = { readonly marathonForYear: MarathonNode; readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; - readonly me: GetPersonResponse; + readonly me?: Maybe; readonly node: Node; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; - readonly person: GetPersonResponse; - readonly personByLinkBlue: GetPersonResponse; + readonly person: PersonNode; + readonly personByLinkBlue: PersonNode; readonly pointEntries: ListPointEntriesResponse; readonly pointEntry: GetPointEntryByUuidResponse; readonly pointOpportunities: ListPointOpportunitiesResponse; readonly pointOpportunity: SinglePointOpportunityResponse; - readonly searchPeopleByName: GetPeopleResponse; + readonly searchPeopleByName: ReadonlyArray; readonly team: SingleTeamResponse; readonly teams: ListTeamsResponse; }; @@ -2197,7 +2167,7 @@ export type PersonSearchQueryVariables = Exact<{ }>; -export type PersonSearchQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null }> }, readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; +export type PersonSearchQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null }>, readonly personByLinkBlue: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } }; export type SingleNotificationFragmentFragment = { readonly __typename?: 'NotificationNode', readonly id: string, readonly title: string, readonly body: string, readonly deliveryIssue?: string | null, readonly deliveryIssueAcknowledgedAt?: Date | string | null, readonly sendAt?: Date | string | null, readonly startedSendingAt?: Date | string | null, readonly createdAt?: Date | string | null, readonly deliveryCount: number, readonly deliveryIssueCount: { readonly __typename?: 'NotificationDeliveryIssueCount', readonly DeviceNotRegistered: number, readonly InvalidCredentials: number, readonly MessageRateExceeded: number, readonly MessageTooBig: number, readonly MismatchSenderId: number, readonly Unknown: number } } & { ' $fragmentName'?: 'SingleNotificationFragmentFragment' }; @@ -2248,7 +2218,7 @@ export type PersonCreatorMutationVariables = Exact<{ }>; -export type PersonCreatorMutation = { readonly __typename?: 'Mutation', readonly createPerson: { readonly __typename?: 'CreatePersonResponse', readonly ok: boolean, readonly uuid: string } }; +export type PersonCreatorMutation = { readonly __typename?: 'Mutation', readonly createPerson: { readonly __typename?: 'PersonNode', readonly id: string } }; export type PersonEditorFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }> } & { ' $fragmentName'?: 'PersonEditorFragmentFragment' }; @@ -2258,7 +2228,7 @@ export type PersonEditorMutationVariables = Exact<{ }>; -export type PersonEditorMutation = { readonly __typename?: 'Mutation', readonly setPerson: { readonly __typename?: 'GetPersonResponse', readonly ok: boolean } }; +export type PersonEditorMutation = { readonly __typename?: 'Mutation', readonly setPerson: { readonly __typename?: 'PersonNode', readonly id: string } }; export type CreatePointEntryMutationVariables = Exact<{ input: CreatePointEntryInput; @@ -2272,21 +2242,21 @@ export type GetPersonByUuidQueryVariables = Exact<{ }>; -export type GetPersonByUuidQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } | null } }; +export type GetPersonByUuidQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null } }; export type GetPersonByLinkBlueQueryVariables = Exact<{ linkBlue: Scalars['String']['input']; }>; -export type GetPersonByLinkBlueQuery = { readonly __typename?: 'Query', readonly personByLinkBlue: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null } | null } }; +export type GetPersonByLinkBlueQuery = { readonly __typename?: 'Query', readonly personByLinkBlue: { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null } }; export type SearchPersonByNameQueryVariables = Exact<{ name: Scalars['String']['input']; }>; -export type SearchPersonByNameQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: { readonly __typename?: 'GetPeopleResponse', readonly data: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null }> } }; +export type SearchPersonByNameQuery = { readonly __typename?: 'Query', readonly searchPeopleByName: ReadonlyArray<{ readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null }> }; export type CreatePersonByLinkBlueMutationVariables = Exact<{ linkBlue: Scalars['String']['input']; @@ -2295,7 +2265,7 @@ export type CreatePersonByLinkBlueMutationVariables = Exact<{ }>; -export type CreatePersonByLinkBlueMutation = { readonly __typename?: 'Mutation', readonly createPerson: { readonly __typename?: 'CreatePersonResponse', readonly uuid: string } }; +export type CreatePersonByLinkBlueMutation = { readonly __typename?: 'Mutation', readonly createPerson: { readonly __typename?: 'PersonNode', readonly id: string } }; export type PointEntryOpportunityLookupQueryVariables = Exact<{ name: Scalars['String']['input']; @@ -2416,7 +2386,7 @@ export type DeletePersonMutationVariables = Exact<{ }>; -export type DeletePersonMutation = { readonly __typename?: 'Mutation', readonly deletePerson: { readonly __typename?: 'DeletePersonResponse', readonly ok: boolean } }; +export type DeletePersonMutation = { readonly __typename?: 'Mutation', readonly deletePerson: { readonly __typename?: 'PersonNode', readonly id: string } }; export type PersonViewerFragmentFragment = { readonly __typename?: 'PersonNode', readonly id: string, readonly name?: string | null, readonly linkblue?: string | null, readonly email: string, readonly dbRole: DbRole, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly position: MembershipPositionType, readonly team: { readonly __typename?: 'TeamNode', readonly id: string, readonly name: string } }>, readonly committees: ReadonlyArray<{ readonly __typename?: 'CommitteeMembershipNode', readonly identifier: CommitteeIdentifier, readonly role: CommitteeRole }> } & { ' $fragmentName'?: 'PersonViewerFragmentFragment' }; @@ -2668,10 +2638,10 @@ export type EditPersonPageQueryVariables = Exact<{ }>; -export type EditPersonPageQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonNode' } - & { ' $fragmentRefs'?: { 'PersonEditorFragmentFragment': PersonEditorFragmentFragment } } - ) | null }, readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( +export type EditPersonPageQuery = { readonly __typename?: 'Query', readonly person: ( + { readonly __typename?: 'PersonNode' } + & { ' $fragmentRefs'?: { 'PersonEditorFragmentFragment': PersonEditorFragmentFragment } } + ), readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'TeamNameFragmentFragment': TeamNameFragmentFragment } } )> } }; @@ -2681,10 +2651,10 @@ export type ViewPersonPageQueryVariables = Exact<{ }>; -export type ViewPersonPageQuery = { readonly __typename?: 'Query', readonly person: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonNode' } - & { ' $fragmentRefs'?: { 'PersonViewerFragmentFragment': PersonViewerFragmentFragment } } - ) | null } }; +export type ViewPersonPageQuery = { readonly __typename?: 'Query', readonly person: ( + { readonly __typename?: 'PersonNode' } + & { ' $fragmentRefs'?: { 'PersonViewerFragmentFragment': PersonViewerFragmentFragment } } + ) }; export type EditTeamPageQueryVariables = Exact<{ uuid: Scalars['GlobalId']['input']; @@ -2737,19 +2707,19 @@ export const MarathonViewerFragmentFragmentDoc = {"kind":"Document","definitions export const ActiveMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"marathons"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}}]}}]}}]} as unknown as DocumentNode; export const SelectedMarathonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SelectedMarathon"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marathon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}},{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; export const ImagePickerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ImagePicker"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ImageResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"images"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"IntValue","value":"9"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]} as unknown as DocumentNode; -export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const PersonSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]} as unknown as DocumentNode; export const CreateNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"title"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"body"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"audience"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationAudienceInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"url"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stageNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"title"},"value":{"kind":"Variable","name":{"kind":"Name","value":"title"}}},{"kind":"Argument","name":{"kind":"Name","value":"body"},"value":{"kind":"Variable","name":{"kind":"Name","value":"body"}}},{"kind":"Argument","name":{"kind":"Name","value":"audience"},"value":{"kind":"Variable","name":{"kind":"Name","value":"audience"}}},{"kind":"Argument","name":{"kind":"Name","value":"url"},"value":{"kind":"Variable","name":{"kind":"Name","value":"url"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const CancelNotificationScheduleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelNotificationSchedule"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"abortScheduledNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeleteNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"force"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"force"},"value":{"kind":"Variable","name":{"kind":"Name","value":"force"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const SendNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"sendNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const ScheduleNotificationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ScheduleNotification"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scheduleNotification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"sendAt"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sendAt"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const PersonCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; -export const PersonEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetPersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const PersonCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; +export const PersonEditorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PersonEditor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SetPersonInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const CreatePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointEntryInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetPersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const SearchPersonByNameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPersonByName"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; -export const CreatePersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EmailAddress"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"linkblue"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"memberOf"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; +export const GetPersonByUuidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByUuid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]} as unknown as DocumentNode; +export const GetPersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetPersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personByLinkBlue"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"linkBlueId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const SearchPersonByNameDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchPersonByName"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"searchPeopleByName"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const CreatePersonByLinkBlueDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePersonByLinkBlue"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"EmailAddress"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"linkblue"},"value":{"kind":"Variable","name":{"kind":"Name","value":"linkBlue"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"memberOf"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const PointEntryOpportunityLookupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PointEntryOpportunityLookup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pointOpportunities"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"name"}},{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"SUBSTRING"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreatePointOpportunityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePointOpportunity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreatePointOpportunityInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPointOpportunity"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; export const TeamCreatorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TeamCreator"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateTeamInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}},{"kind":"Argument","name":{"kind":"Name","value":"marathon"},"value":{"kind":"Variable","name":{"kind":"Name","value":"marathonUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}},{"kind":"Field","name":{"kind":"Name","value":"uuid"}}]}}]}}]} as unknown as DocumentNode; @@ -2759,7 +2729,7 @@ export const TeamsTableDocument = {"kind":"Document","definitions":[{"kind":"Ope export const NotificationDeliveriesTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationDeliveriesTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryResolverKeyedIsNullFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"notificationUuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"notificationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveriesTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryError"}},{"kind":"Field","name":{"kind":"Name","value":"receiptCheckedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}}]}}]} as unknown as DocumentNode; export const NotificationsTableQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationsTableQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SortDirection"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedDateFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedIsNullFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedOneOfFilterItem"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationResolverKeyedStringFilterItem"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notifications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"sortDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dateFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"isNullFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isNullFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"oneOfFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oneOfFilters"}}},{"kind":"Argument","name":{"kind":"Name","value":"stringFilters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stringFilters"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"pageSize"}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationsTableFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationsTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}}]}}]} as unknown as DocumentNode; export const DeletePointEntryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePointEntry"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePointEntry"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; -export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; +export const DeletePersonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePerson"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePerson"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const DeleteTeamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTeam"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteTeam"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const LoginStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LoginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"effectiveCommitteeRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"identifier"}}]}}]}}]}}]} as unknown as DocumentNode; export const CommitConfigChangesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CommitConfigChanges"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"changes"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateConfigurationInput"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createConfigurations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"changes"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; @@ -2786,8 +2756,8 @@ export const EditMarathonHourDocument = {"kind":"Document","definitions":[{"kind export const NotificationManagerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationManager"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; export const NotificationViewerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NotificationViewer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notification"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SingleNotificationFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SingleNotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssue"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueAcknowledgedAt"}},{"kind":"Field","name":{"kind":"Name","value":"sendAt"}},{"kind":"Field","name":{"kind":"Name","value":"startedSendingAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryCount"}},{"kind":"Field","name":{"kind":"Name","value":"deliveryIssueCount"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"DeviceNotRegistered"}},{"kind":"Field","name":{"kind":"Name","value":"InvalidCredentials"}},{"kind":"Field","name":{"kind":"Name","value":"MessageRateExceeded"}},{"kind":"Field","name":{"kind":"Name","value":"MessageTooBig"}},{"kind":"Field","name":{"kind":"Name","value":"MismatchSenderId"}},{"kind":"Field","name":{"kind":"Name","value":"Unknown"}}]}}]}}]} as unknown as DocumentNode; export const CreatePersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CreatePersonPage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; -export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; +export const EditPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonEditorFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"asc"}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamNameFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamNameFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode; +export const ViewPersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewPersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PersonViewerFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PersonViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"committees"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EditTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"EditTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"uuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamEditorFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamEditorFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ViewTeamFundraisingDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamFundraisingDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fundraisingEntries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"donatedByText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedToText"}},{"kind":"Field","name":{"kind":"Name","value":"donatedOn"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ViewTeamPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ViewTeamPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"teamUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TeamViewerFragment"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PointEntryTableFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TeamViewerFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"marathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"year"}}]}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"position"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PointEntryTableFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PointEntryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"pointOpportunity"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"opportunityDate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"comment"}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-public/gql.ts index 6c56926b..b7710966 100644 --- a/packages/common/lib/graphql-client-public/gql.ts +++ b/packages/common/lib/graphql-client-public/gql.ts @@ -20,15 +20,15 @@ const documents = { "\n fragment NotificationDeliveryFragment on NotificationDeliveryNode {\n id\n sentAt\n notification {\n ...NotificationFragment\n }\n }\n": types.NotificationDeliveryFragmentFragmentDoc, "\n query useAllowedLoginTypes {\n activeConfiguration(key: \"ALLOWED_LOGIN_TYPES\") {\n data {\n ...SimpleConfig\n }\n }\n }\n": types.UseAllowedLoginTypesDocument, "\n query MarathonTime {\n latestMarathon {\n startDate\n endDate\n }\n }\n": types.MarathonTimeDocument, - "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n data {\n linkblue\n }\n }\n }\n": types.UseTabBarConfigDocument, - "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n ": types.TriviaCrackDocument, - "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, + "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n linkblue\n }\n }\n": types.UseTabBarConfigDocument, + "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n ": types.TriviaCrackDocument, + "\n query AuthState {\n me {\n id\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n": types.AuthStateDocument, "\n mutation SetDevice($input: RegisterDeviceInput!) {\n registerDevice(input: $input) {\n ok\n }\n }\n": types.SetDeviceDocument, "\n fragment EventScreenFragment on EventNode {\n id\n title\n summary\n description\n location\n occurrences {\n id\n interval {\n start\n end\n }\n fullDay\n }\n images {\n thumbHash\n url\n height\n width\n alt\n mimeType\n }\n }\n": types.EventScreenFragmentFragmentDoc, "\n query DeviceNotifications(\n $deviceUuid: GlobalId!\n $page: Int\n $pageSize: Int\n $verifier: String!\n ) {\n device(uuid: $deviceUuid) {\n data {\n notificationDeliveries(\n pageSize: $pageSize\n page: $page\n verifier: $verifier\n ) {\n ...NotificationDeliveryFragment\n }\n }\n }\n }\n": types.DeviceNotificationsDocument, "\n fragment ProfileScreenAuthFragment on LoginState {\n dbRole\n authSource\n }\n": types.ProfileScreenAuthFragmentFragmentDoc, "\n fragment ProfileScreenUserFragment on PersonNode {\n name\n linkblue\n teams {\n position\n team {\n name\n }\n }\n primaryCommittee {\n identifier\n role\n }\n }\n": types.ProfileScreenUserFragmentFragmentDoc, - "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n": types.RootScreenDocumentDocument, + "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n ...ProfileScreenUserFragment\n }\n }\n": types.RootScreenDocumentDocument, "\n fragment RootScreenAuthFragment on LoginState {\n dbRole\n }\n": types.RootScreenAuthFragmentFragmentDoc, "\n query Events(\n $earliestTimestamp: DateTimeISO!\n $lastTimestamp: DateTimeISO!\n ) {\n events(\n dateFilters: [\n {\n comparison: GREATER_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $earliestTimestamp\n }\n {\n comparison: LESS_THAN_OR_EQUAL_TO\n field: occurrenceStart\n value: $lastTimestamp\n }\n ]\n sortDirection: asc\n sortBy: \"occurrence\"\n ) {\n data {\n ...EventScreenFragment\n }\n }\n }\n ": types.EventsDocument, "\n query ServerFeed {\n feed(limit: 20) {\n id\n title\n createdAt\n textContent\n image {\n url\n alt\n width\n height\n thumbHash\n }\n }\n }\n": types.ServerFeedDocument, @@ -36,7 +36,7 @@ const documents = { "\n query MarathonScreen {\n currentMarathonHour {\n ...HourScreenFragment\n }\n latestMarathon {\n startDate\n endDate\n hours {\n ...HourScreenFragment\n }\n }\n }\n": types.MarathonScreenDocument, "\n fragment ScoreBoardFragment on TeamNode {\n id\n name\n totalPoints\n legacyStatus\n type\n }\n": types.ScoreBoardFragmentFragmentDoc, "\n fragment HighlightedTeamFragment on TeamNode {\n id\n name\n legacyStatus\n type\n }\n": types.HighlightedTeamFragmentFragmentDoc, - "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, + "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n": types.ScoreBoardDocumentDocument, "\n query ActiveMarathonDocument {\n currentMarathon {\n id\n }\n }\n": types.ActiveMarathonDocumentDocument, "\n fragment MyTeamFragment on TeamNode {\n id\n name\n totalPoints\n pointEntries {\n personFrom {\n id\n name\n linkblue\n }\n points\n }\n members {\n position\n person {\n linkblue\n name\n }\n }\n }\n": types.MyTeamFragmentFragmentDoc, }; @@ -86,15 +86,15 @@ export function graphql(source: "\n query MarathonTime {\n latestMarathon {\ /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n data {\n linkblue\n }\n }\n }\n"): (typeof documents)["\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n data {\n linkblue\n }\n }\n }\n"]; +export function graphql(source: "\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n linkblue\n }\n }\n"): (typeof documents)["\n query useTabBarConfig {\n activeConfiguration(key: \"TAB_BAR_CONFIG\") {\n data {\n ...SimpleConfig\n }\n }\n me {\n linkblue\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n "): (typeof documents)["\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n data {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n }\n "]; +export function graphql(source: "\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n "): (typeof documents)["\n query TriviaCrack {\n activeConfiguration(key: \"TRIVIA_CRACK\") {\n data {\n ...SimpleConfig\n }\n }\n\n me {\n teams {\n team {\n type\n name\n }\n }\n }\n }\n "]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"): (typeof documents)["\n query AuthState {\n me {\n data {\n id\n }\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"]; +export function graphql(source: "\n query AuthState {\n me {\n id\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"): (typeof documents)["\n query AuthState {\n me {\n id\n }\n loginState {\n dbRole\n loggedIn\n authSource\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -118,7 +118,7 @@ export function graphql(source: "\n fragment ProfileScreenUserFragment on Perso /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n"): (typeof documents)["\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n data {\n ...ProfileScreenUserFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n ...ProfileScreenUserFragment\n }\n }\n"): (typeof documents)["\n query RootScreenDocument {\n loginState {\n ...ProfileScreenAuthFragment\n ...RootScreenAuthFragment\n }\n me {\n ...ProfileScreenUserFragment\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -150,7 +150,7 @@ export function graphql(source: "\n fragment HighlightedTeamFragment on TeamNod /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n data {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; +export function graphql(source: "\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"): (typeof documents)["\n query ScoreBoardDocument($type: [TeamType!]) {\n me {\n id\n teams {\n team {\n ...HighlightedTeamFragment\n ...MyTeamFragment\n }\n }\n }\n teams(\n sendAll: true\n sortBy: [\"totalPoints\", \"name\"]\n sortDirection: [desc, asc]\n type: $type\n ) {\n data {\n ...ScoreBoardFragment\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-public/graphql.ts index b522eabc..87aa9b9d 100644 --- a/packages/common/lib/graphql-client-public/graphql.ts +++ b/packages/common/lib/graphql-client-public/graphql.ts @@ -212,13 +212,6 @@ export type CreatePersonInput = { readonly name?: InputMaybe; }; -export type CreatePersonResponse = AbstractGraphQlCreatedResponse & AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'CreatePersonResponse'; - readonly data: PersonNode; - readonly ok: Scalars['Boolean']['output']; - readonly uuid: Scalars['String']['output']; -}; - export type CreatePointEntryInput = { readonly comment?: InputMaybe; readonly opportunityUuid?: InputMaybe; @@ -296,11 +289,6 @@ export type DeleteNotificationResponse = AbstractGraphQlOkResponse & GraphQlBase readonly ok: Scalars['Boolean']['output']; }; -export type DeletePersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'DeletePersonResponse'; - readonly ok: Scalars['Boolean']['output']; -}; - export type DeletePointEntryResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'DeletePointEntryResponse'; readonly ok: Scalars['Boolean']['output']; @@ -620,30 +608,12 @@ export type GetImageByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResp readonly ok: Scalars['Boolean']['output']; }; -export type GetMembershipResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetMembershipResponse'; - readonly data?: Maybe; - readonly ok: Scalars['Boolean']['output']; -}; - export type GetNotificationByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetNotificationByUuidResponse'; readonly data: NotificationNode; readonly ok: Scalars['Boolean']['output']; }; -export type GetPeopleResponse = AbstractGraphQlArrayOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetPeopleResponse'; - readonly data: ReadonlyArray; - readonly ok: Scalars['Boolean']['output']; -}; - -export type GetPersonResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { - readonly __typename?: 'GetPersonResponse'; - readonly data?: Maybe; - readonly ok: Scalars['Boolean']['output']; -}; - export type GetPointEntryByUuidResponse = AbstractGraphQlOkResponse & GraphQlBaseResponse & { readonly __typename?: 'GetPointEntryByUuidResponse'; readonly data: PointEntryNode; @@ -977,7 +947,7 @@ export type Mutation = { readonly acknowledgeDeliveryIssue: AcknowledgeDeliveryIssueResponse; readonly addExistingImageToEvent: AddEventImageResponse; readonly addMap: MarathonHourNode; - readonly addPersonToTeam: GetMembershipResponse; + readonly addPersonToTeam: MembershipNode; readonly assignEntryToPerson: FundraisingAssignmentNode; readonly assignTeamToDbFundsTeam: Scalars['Void']['output']; readonly attachImageToFeedItem: FeedNode; @@ -988,7 +958,7 @@ export type Mutation = { readonly createImage: ImageNode; readonly createMarathon: MarathonNode; readonly createMarathonHour: MarathonHourNode; - readonly createPerson: CreatePersonResponse; + readonly createPerson: PersonNode; readonly createPointEntry: CreatePointEntryResponse; readonly createPointOpportunity: CreatePointOpportunityResponse; readonly createTeam: CreateTeamResponse; @@ -1001,7 +971,7 @@ export type Mutation = { readonly deleteMarathon: Scalars['Void']['output']; readonly deleteMarathonHour: Scalars['Void']['output']; readonly deleteNotification: DeleteNotificationResponse; - readonly deletePerson: DeletePersonResponse; + readonly deletePerson: PersonNode; readonly deletePointEntry: DeletePointEntryResponse; readonly deletePointOpportunity: DeletePointOpportunityResponse; readonly deleteTeam: DeleteTeamResponse; @@ -1018,7 +988,7 @@ export type Mutation = { readonly setImageUrl: ImageNode; readonly setMarathon: MarathonNode; readonly setMarathonHour: MarathonHourNode; - readonly setPerson: GetPersonResponse; + readonly setPerson: PersonNode; readonly setPointOpportunity: SinglePointOpportunityResponse; readonly setTeam: SingleTeamResponse; readonly stageNotification: StageNotificationResponse; @@ -1672,18 +1642,18 @@ export type Query = { readonly marathonForYear: MarathonNode; readonly marathonHour: MarathonHourNode; readonly marathons: ListMarathonsResponse; - readonly me: GetPersonResponse; + readonly me?: Maybe; readonly node: Node; readonly notification: GetNotificationByUuidResponse; readonly notificationDeliveries: ListNotificationDeliveriesResponse; readonly notifications: ListNotificationsResponse; - readonly person: GetPersonResponse; - readonly personByLinkBlue: GetPersonResponse; + readonly person: PersonNode; + readonly personByLinkBlue: PersonNode; readonly pointEntries: ListPointEntriesResponse; readonly pointEntry: GetPointEntryByUuidResponse; readonly pointOpportunities: ListPointOpportunitiesResponse; readonly pointOpportunity: SinglePointOpportunityResponse; - readonly searchPeopleByName: GetPeopleResponse; + readonly searchPeopleByName: ReadonlyArray; readonly team: SingleTeamResponse; readonly teams: ListTeamsResponse; }; @@ -2208,7 +2178,7 @@ export type UseTabBarConfigQueryVariables = Exact<{ [key: string]: never; }>; export type UseTabBarConfigQuery = { readonly __typename?: 'Query', readonly activeConfiguration: { readonly __typename?: 'GetConfigurationByUuidResponse', readonly data: ( { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } - ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly linkblue?: string | null } | null } }; + ) }, readonly me?: { readonly __typename?: 'PersonNode', readonly linkblue?: string | null } | null }; export type TriviaCrackQueryVariables = Exact<{ [key: string]: never; }>; @@ -2216,12 +2186,12 @@ export type TriviaCrackQueryVariables = Exact<{ [key: string]: never; }>; export type TriviaCrackQuery = { readonly __typename?: 'Query', readonly activeConfiguration: { readonly __typename?: 'GetConfigurationByUuidResponse', readonly data: ( { readonly __typename?: 'ConfigurationNode' } & { ' $fragmentRefs'?: { 'SimpleConfigFragment': SimpleConfigFragment } } - ) }, readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: { readonly __typename?: 'TeamNode', readonly type: TeamType, readonly name: string } }> } | null } }; + ) }, readonly me?: { readonly __typename?: 'PersonNode', readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: { readonly __typename?: 'TeamNode', readonly type: TeamType, readonly name: string } }> } | null }; export type AuthStateQueryVariables = Exact<{ [key: string]: never; }>; -export type AuthStateQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string } | null }, readonly loginState: { readonly __typename?: 'LoginState', readonly dbRole: DbRole, readonly loggedIn: boolean, readonly authSource: AuthSource } }; +export type AuthStateQuery = { readonly __typename?: 'Query', readonly me?: { readonly __typename?: 'PersonNode', readonly id: string } | null, readonly loginState: { readonly __typename?: 'LoginState', readonly dbRole: DbRole, readonly loggedIn: boolean, readonly authSource: AuthSource } }; export type SetDeviceMutationVariables = Exact<{ input: RegisterDeviceInput; @@ -2255,10 +2225,10 @@ export type RootScreenDocumentQueryVariables = Exact<{ [key: string]: never; }>; export type RootScreenDocumentQuery = { readonly __typename?: 'Query', readonly loginState: ( { readonly __typename?: 'LoginState' } & { ' $fragmentRefs'?: { 'ProfileScreenAuthFragmentFragment': ProfileScreenAuthFragmentFragment;'RootScreenAuthFragmentFragment': RootScreenAuthFragmentFragment } } - ), readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: ( - { readonly __typename?: 'PersonNode' } - & { ' $fragmentRefs'?: { 'ProfileScreenUserFragmentFragment': ProfileScreenUserFragmentFragment } } - ) | null } }; + ), readonly me?: ( + { readonly __typename?: 'PersonNode' } + & { ' $fragmentRefs'?: { 'ProfileScreenUserFragmentFragment': ProfileScreenUserFragmentFragment } } + ) | null }; export type RootScreenAuthFragmentFragment = { readonly __typename?: 'LoginState', readonly dbRole: DbRole } & { ' $fragmentName'?: 'RootScreenAuthFragmentFragment' }; @@ -2303,10 +2273,10 @@ export type ScoreBoardDocumentQueryVariables = Exact<{ }>; -export type ScoreBoardDocumentQuery = { readonly __typename?: 'Query', readonly me: { readonly __typename?: 'GetPersonResponse', readonly data?: { readonly __typename?: 'PersonNode', readonly id: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: ( - { readonly __typename?: 'TeamNode' } - & { ' $fragmentRefs'?: { 'HighlightedTeamFragmentFragment': HighlightedTeamFragmentFragment;'MyTeamFragmentFragment': MyTeamFragmentFragment } } - ) }> } | null }, readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( +export type ScoreBoardDocumentQuery = { readonly __typename?: 'Query', readonly me?: { readonly __typename?: 'PersonNode', readonly id: string, readonly teams: ReadonlyArray<{ readonly __typename?: 'MembershipNode', readonly team: ( + { readonly __typename?: 'TeamNode' } + & { ' $fragmentRefs'?: { 'HighlightedTeamFragmentFragment': HighlightedTeamFragmentFragment;'MyTeamFragmentFragment': MyTeamFragmentFragment } } + ) }> } | null, readonly teams: { readonly __typename?: 'ListTeamsResponse', readonly data: ReadonlyArray<( { readonly __typename?: 'TeamNode' } & { ' $fragmentRefs'?: { 'ScoreBoardFragmentFragment': ScoreBoardFragmentFragment } } )> } }; @@ -2333,14 +2303,14 @@ export const HighlightedTeamFragmentFragmentDoc = {"kind":"Document","definition export const MyTeamFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]} as unknown as DocumentNode; export const UseAllowedLoginTypesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useAllowedLoginTypes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"ALLOWED_LOGIN_TYPES","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; export const MarathonTimeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonTime"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}}]}}]}}]} as unknown as DocumentNode; -export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useTabBarConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TAB_BAR_CONFIG","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; -export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; +export const UseTabBarConfigDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"useTabBarConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TAB_BAR_CONFIG","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const TriviaCrackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"TriviaCrack"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConfiguration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"StringValue","value":"TRIVIA_CRACK","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SimpleConfig"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SimpleConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ConfigurationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]} as unknown as DocumentNode; +export const AuthStateDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"loggedIn"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}}]}}]} as unknown as DocumentNode; export const SetDeviceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetDevice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RegisterDeviceInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"registerDevice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ok"}}]}}]}}]} as unknown as DocumentNode; export const DeviceNotificationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DeviceNotifications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"GlobalId"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"device"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"uuid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"deviceUuid"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"notificationDeliveries"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"verifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"verifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationDeliveryFragment"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"body"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NotificationDeliveryFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NotificationDeliveryNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"sentAt"}},{"kind":"Field","name":{"kind":"Name","value":"notification"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NotificationFragment"}}]}}]}}]} as unknown as DocumentNode; -export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; +export const RootScreenDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"RootScreenDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"loginState"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenAuthFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"RootScreenAuthFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileScreenUserFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}},{"kind":"Field","name":{"kind":"Name","value":"authSource"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RootScreenAuthFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LoginState"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dbRole"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileScreenUserFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PersonNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"primaryCommittee"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"identifier"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]} as unknown as DocumentNode; export const EventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Events"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTimeISO"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"dateFilters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"GREATER_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"earliestTimestamp"}}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"comparison"},"value":{"kind":"EnumValue","value":"LESS_THAN_OR_EQUAL_TO"}},{"kind":"ObjectField","name":{"kind":"Name","value":"field"},"value":{"kind":"EnumValue","value":"occurrenceStart"}},{"kind":"ObjectField","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastTimestamp"}}}]}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"EnumValue","value":"asc"}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"StringValue","value":"occurrence","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"EventScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"EventScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"EventNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"summary"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"occurrences"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"interval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start"}},{"kind":"Field","name":{"kind":"Name","value":"end"}}]}},{"kind":"Field","name":{"kind":"Name","value":"fullDay"}}]}},{"kind":"Field","name":{"kind":"Name","value":"images"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}}]}}]} as unknown as DocumentNode; export const ServerFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerFeed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"image"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarathonScreenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarathonScreen"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathonHour"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"latestMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"startDate"}},{"kind":"Field","name":{"kind":"Name","value":"endDate"}},{"kind":"Field","name":{"kind":"Name","value":"hours"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HourScreenFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ImageViewFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ImageNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"thumbHash"}},{"kind":"Field","name":{"kind":"Name","value":"alt"}},{"kind":"Field","name":{"kind":"Name","value":"width"}},{"kind":"Field","name":{"kind":"Name","value":"height"}},{"kind":"Field","name":{"kind":"Name","value":"mimeType"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HourScreenFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"MarathonHourNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"durationInfo"}},{"kind":"Field","name":{"kind":"Name","value":"mapImages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ImageViewFragment"}}]}}]}}]} as unknown as DocumentNode; -export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"desc"},{"kind":"EnumValue","value":"asc"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; +export const ScoreBoardDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ScoreBoardDocument"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TeamType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"HighlightedTeamFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"MyTeamFragment"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"teams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"sendAll"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"sortBy"},"value":{"kind":"ListValue","values":[{"kind":"StringValue","value":"totalPoints","block":false},{"kind":"StringValue","value":"name","block":false}]}},{"kind":"Argument","name":{"kind":"Name","value":"sortDirection"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"desc"},{"kind":"EnumValue","value":"asc"}]}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ScoreBoardFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"HighlightedTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MyTeamFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"pointEntries"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personFrom"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"linkblue"}}]}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"members"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"linkblue"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ScoreBoardFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TeamNode"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalPoints"}},{"kind":"Field","name":{"kind":"Name","value":"legacyStatus"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]} as unknown as DocumentNode; export const ActiveMarathonDocumentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ActiveMarathonDocument"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentMarathon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/packages/mobile/src/common/hooks/useTabBarConfig.ts b/packages/mobile/src/common/hooks/useTabBarConfig.ts index 6e09095e..eee06d2d 100644 --- a/packages/mobile/src/common/hooks/useTabBarConfig.ts +++ b/packages/mobile/src/common/hooks/useTabBarConfig.ts @@ -15,9 +15,7 @@ const useTabBarConfigQuery = graphql(/* GraphQL */ ` } } me { - data { - linkblue - } + linkblue } } `); diff --git a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx index d5c2b483..ce0c4547 100644 --- a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx +++ b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx @@ -47,12 +47,10 @@ export function TriviaCrack() { } me { - data { - teams { - team { - type - name - } + teams { + team { + type + name } } } @@ -67,7 +65,7 @@ export function TriviaCrack() { ); const { stationOrder, moraleTeamNumber } = useMemo(() => { - const value = JSON.parse(option?.value || "{}") as unknown; + const value = JSON.parse(option.value || "{}") as unknown; let stationOrder: [number, number, number, number, number, number] | null = null; let moraleTeamNumber: number | undefined; @@ -112,7 +110,7 @@ export function TriviaCrack() { } } return { stationOrder, moraleTeamNumber }; - }, [data?.me.data?.teams, option?.value]); + }, [data?.me.data?.teams, option.value]); useEffect(() => { if (stationOrder && spins == null) { diff --git a/packages/mobile/src/context/auth.tsx b/packages/mobile/src/context/auth.tsx index e1b05f82..cdff846e 100644 --- a/packages/mobile/src/context/auth.tsx +++ b/packages/mobile/src/context/auth.tsx @@ -24,9 +24,7 @@ const authStateContext = createContext({ const authStateDocument = graphql(/* GraphQL */ ` query AuthState { me { - data { - id - } + id } loginState { dbRole diff --git a/packages/mobile/src/navigation/root/RootScreen.tsx b/packages/mobile/src/navigation/root/RootScreen.tsx index 97242777..55a6dd52 100644 --- a/packages/mobile/src/navigation/root/RootScreen.tsx +++ b/packages/mobile/src/navigation/root/RootScreen.tsx @@ -32,9 +32,7 @@ const rootScreenDocument = graphql(/* GraphQL */ ` ...RootScreenAuthFragment } me { - data { - ...ProfileScreenUserFragment - } + ...ProfileScreenUserFragment } } `); @@ -70,7 +68,7 @@ const RootScreen = () => { rootScreenData?.loginState ?? null ); const isLoggedIn = useMemo(() => { - return authData?.dbRole !== DbRole.None; + return authData.dbRole !== DbRole.None; }, [authData]); const { colors } = useTheme(); diff --git a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx index 7857f9fb..36321489 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx @@ -14,13 +14,11 @@ import TeamScreen from "./TeamScreen"; const scoreBoardDocument = graphql(/* GraphQL */ ` query ScoreBoardDocument($type: [TeamType!]) { me { - data { - id - teams { - team { - ...HighlightedTeamFragment - ...MyTeamFragment - } + id + teams { + team { + ...HighlightedTeamFragment + ...MyTeamFragment } } } diff --git a/packages/portal/src/elements/components/PersonSearch.tsx b/packages/portal/src/elements/components/PersonSearch.tsx index 2e4e65d2..c7825a61 100644 --- a/packages/portal/src/elements/components/PersonSearch.tsx +++ b/packages/portal/src/elements/components/PersonSearch.tsx @@ -7,18 +7,14 @@ import { useQuery } from "urql"; const personSearchDocument = graphql(/* GraphQL */ ` query PersonSearch($search: String!) { searchPeopleByName(name: $search) { - data { - id - name - linkblue - } + id + name + linkblue } personByLinkBlue(linkBlueId: $search) { - data { - id - name - linkblue - } + id + name + linkblue } } `); @@ -48,19 +44,19 @@ export function PersonSearch({ }); const options = - data?.searchPeopleByName.data.map((person) => ({ + data?.searchPeopleByName.map((person) => ({ value: person.name, label: person.name, person, })) || []; - if (data?.personByLinkBlue.data) { + if (data?.personByLinkBlue) { options.push({ - value: data.personByLinkBlue.data.id, - label: data.personByLinkBlue.data.linkblue - ? `${data.personByLinkBlue.data.name} (${data.personByLinkBlue.data.linkblue})` - : data.personByLinkBlue.data.name, - person: data.personByLinkBlue.data, + value: data.personByLinkBlue.id, + label: data.personByLinkBlue.linkblue + ? `${data.personByLinkBlue.name} (${data.personByLinkBlue.linkblue})` + : data.personByLinkBlue.name, + person: data.personByLinkBlue, }); } diff --git a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx index b3dd4310..debc8835 100644 --- a/packages/portal/src/elements/forms/person/create/PersonCreator.tsx +++ b/packages/portal/src/elements/forms/person/create/PersonCreator.tsx @@ -21,10 +21,10 @@ export function PersonCreator({ const { message } = App.useApp(); const { formApi } = usePersonCreatorForm((ret) => { - if (ret?.uuid) { + if (ret?.id) { navigate({ to: "/people/$personId/", - params: { personId: ret.uuid }, + params: { personId: ret.id }, }).catch((error: unknown) => console.error(error)); } }); diff --git a/packages/portal/src/elements/forms/person/create/PersonCreatorGQL.ts b/packages/portal/src/elements/forms/person/create/PersonCreatorGQL.ts index 68f4addb..dba194e5 100644 --- a/packages/portal/src/elements/forms/person/create/PersonCreatorGQL.ts +++ b/packages/portal/src/elements/forms/person/create/PersonCreatorGQL.ts @@ -3,8 +3,7 @@ import { graphql } from "@ukdanceblue/common/graphql-client-admin"; export const personCreatorDocument = graphql(/* GraphQL */ ` mutation PersonCreator($input: CreatePersonInput!) { createPerson(input: $input) { - ok - uuid + id } } `); diff --git a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts index 11a7ce2b..46a57c99 100644 --- a/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts +++ b/packages/portal/src/elements/forms/person/edit/PersonEditorGQL.ts @@ -19,7 +19,7 @@ export const PersonEditorFragment = graphql(/* GraphQL */ ` export const personEditorDocument = graphql(/* GraphQL */ ` mutation PersonEditor($uuid: GlobalId!, $input: SetPersonInput!) { setPerson(uuid: $uuid, input: $input) { - ok + id } } `); diff --git a/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts b/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts index ec9ecc7a..17c58273 100644 --- a/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts +++ b/packages/portal/src/elements/forms/point-entry/create/PointEntryCreatorGQL.ts @@ -13,11 +13,9 @@ export const createPointEntryDocument = graphql(/* GraphQL */ ` export const getPersonByUuidDocument = graphql(/* GraphQL */ ` query GetPersonByUuid($uuid: GlobalId!) { person(uuid: $uuid) { - data { - id - name - linkblue - } + id + name + linkblue } } `); @@ -25,10 +23,8 @@ export const getPersonByUuidDocument = graphql(/* GraphQL */ ` export const getPersonByLinkBlueDocument = graphql(/* GraphQL */ ` query GetPersonByLinkBlue($linkBlue: String!) { personByLinkBlue(linkBlueId: $linkBlue) { - data { - id - name - } + id + name } } `); @@ -36,10 +32,8 @@ export const getPersonByLinkBlueDocument = graphql(/* GraphQL */ ` export const searchPersonByNameDocument = graphql(/* GraphQL */ ` query SearchPersonByName($name: String!) { searchPeopleByName(name: $name) { - data { - id - name - } + id + name } } `); @@ -53,7 +47,7 @@ export const createPersonByLinkBlue = graphql(/* GraphQL */ ` createPerson( input: { email: $email, linkblue: $linkBlue, memberOf: [$teamUuid] } ) { - uuid + id } } `); diff --git a/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx b/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx index fa15f0f0..641964a0 100644 --- a/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx +++ b/packages/portal/src/elements/forms/point-entry/create/PointEntryPersonLookup.tsx @@ -72,12 +72,12 @@ export function PointEntryPersonLookup({ }); useEffect(() => { - if (getPersonByLinkBlueQuery.data?.personByLinkBlue.data) { - setPersonFromUuid(getPersonByLinkBlueQuery.data.personByLinkBlue.data.id); + if (getPersonByLinkBlueQuery.data?.personByLinkBlue) { + setPersonFromUuid(getPersonByLinkBlueQuery.data.personByLinkBlue.id); } }, [ - getPersonByLinkBlueQuery.data?.personByLinkBlue.data, - getPersonByLinkBlueQuery.data?.personByLinkBlue.data?.id, + getPersonByLinkBlueQuery.data?.personByLinkBlue, + getPersonByLinkBlueQuery.data?.personByLinkBlue.id, setPersonFromUuid, ]); @@ -94,7 +94,7 @@ export function PointEntryPersonLookup({ if (linkblueFieldValue) { if ( linkblueFieldValue === searchedForLinkblue && - !getPersonByLinkBlueQuery.data?.personByLinkBlue.data + !getPersonByLinkBlueQuery.data?.personByLinkBlue ) { setLinkblueKnownDoesNotExist(linkblueFieldValue); } else { @@ -102,7 +102,7 @@ export function PointEntryPersonLookup({ } } }, [ - getPersonByLinkBlueQuery.data?.personByLinkBlue.data, + getPersonByLinkBlueQuery.data?.personByLinkBlue, linkblueFieldValue, searchedForLinkblue, ]); @@ -126,9 +126,9 @@ export function PointEntryPersonLookup({ { value: string; label: string }[] >([]); useEffect(() => { - if (searchByNameQuery.data?.searchPeopleByName.data) { + if (searchByNameQuery.data?.searchPeopleByName) { const newNameAutocomplete: typeof nameAutocomplete = []; - for (const person of searchByNameQuery.data.searchPeopleByName.data) { + for (const person of searchByNameQuery.data.searchPeopleByName) { if (person.name) { newNameAutocomplete.push({ value: person.id, @@ -138,7 +138,7 @@ export function PointEntryPersonLookup({ } setNameAutocomplete(newNameAutocomplete); } - }, [searchByNameQuery.data?.searchPeopleByName.data]); + }, [searchByNameQuery.data?.searchPeopleByName]); const updateAutocomplete = useDebouncedCallback( (name: string) => { @@ -192,7 +192,7 @@ export function PointEntryPersonLookup({ placeholder="Search by Name" value={ (personFromUuid && - selectedPersonQuery.data?.person.data?.name) || + selectedPersonQuery.data?.person.name) || searchByNameField } onBlur={field.handleBlur} @@ -218,7 +218,7 @@ export function PointEntryPersonLookup({ name={`${field.name}-linkblue-field`} value={ (personFromUuid && - selectedPersonQuery.data?.person.data?.linkblue) || + selectedPersonQuery.data?.person.linkblue) || linkblueFieldValue } onChange={(e) => { @@ -269,8 +269,8 @@ export function PointEntryPersonLookup({ email: `${linkblueFieldValue}@uky.edu`, teamUuid, }); - if (result.data?.createPerson.uuid) { - setPersonFromUuid(result.data.createPerson.uuid); + if (result.data?.createPerson.id) { + setPersonFromUuid(result.data.createPerson.id); } } catch (error) { showErrorMessage(error); @@ -291,10 +291,10 @@ export function PointEntryPersonLookup({ {field.state.value ? ( <> Selected Person:{" "} - {selectedPersonQuery.data?.person.data ? ( + {selectedPersonQuery.data?.person ? ( - {selectedPersonQuery.data.person.data.name ?? - selectedPersonQuery.data.person.data.linkblue} + {selectedPersonQuery.data.person.name ?? + selectedPersonQuery.data.person.linkblue} ) : ( "No name or linkblue found" diff --git a/packages/portal/src/elements/viewers/person/PersonDeletePopup.tsx b/packages/portal/src/elements/viewers/person/PersonDeletePopup.tsx index 77dd39d5..a70c15a3 100644 --- a/packages/portal/src/elements/viewers/person/PersonDeletePopup.tsx +++ b/packages/portal/src/elements/viewers/person/PersonDeletePopup.tsx @@ -7,7 +7,7 @@ import { useMutation } from "urql"; const deletePersonDocument = graphql(/* GraphQL */ ` mutation DeletePerson($uuid: GlobalId!) { deletePerson(uuid: $uuid) { - ok + id } } `); @@ -33,10 +33,10 @@ export const usePersonDeletePopup = ({ }; useEffect(() => { - if (data?.deletePerson.ok) { + if (data?.deletePerson.id) { setOpen(false); } - }, [data?.deletePerson.ok]); + }, [data?.deletePerson.id]); const PersonDeletePopup = ( <> @@ -46,7 +46,7 @@ export const usePersonDeletePopup = ({ open={open} onOk={() => deletePerson({ uuid }).then((value) => { - if (value.data?.deletePerson.ok) { + if (value.data?.deletePerson.id) { showInfoMessage({ message: "Person successfully deleted", }); diff --git a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx index 3f0607b3..e0cb1f8f 100644 --- a/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx +++ b/packages/portal/src/pages/people/single-person/edit-person/EditPersonPage.tsx @@ -7,9 +7,7 @@ import { useQuery } from "urql"; const viewPersonPageDocument = graphql(/* GraphQL */ ` query EditPersonPage($uuid: GlobalId!) { person(uuid: $uuid) { - data { - ...PersonEditorFragment - } + ...PersonEditorFragment } teams(sendAll: true, sortBy: ["name"], sortDirection: [asc]) { data { @@ -36,7 +34,7 @@ export function EditPersonPage() { return (
    diff --git a/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx b/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx index 0f676764..f26cc6ce 100644 --- a/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx +++ b/packages/portal/src/pages/people/single-person/view-person/ViewPersonPage.tsx @@ -7,9 +7,7 @@ import { useQuery } from "urql"; const viewPersonPageDocument = graphql(/* GraphQL */ ` query ViewPersonPage($uuid: GlobalId!) { person(uuid: $uuid) { - data { - ...PersonViewerFragment - } + ...PersonViewerFragment } } `); @@ -30,7 +28,7 @@ export function ViewPersonPage() { return (
    - +
    ); } From 03896ca47891430f62bf2cfb56b31255910a7ce9 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:06:06 +0000 Subject: [PATCH 138/153] Fix some more issues --- packages/mobile/src/common/hooks/useTabBarConfig.ts | 2 +- .../mobile/src/common/marathonComponents/TriviaCrack.tsx | 8 ++++---- packages/mobile/src/context/auth.tsx | 4 ++-- packages/mobile/src/navigation/root/RootScreen.tsx | 2 +- .../mobile/src/navigation/root/tab/spirit/SpiritStack.tsx | 8 +++----- packages/server/src/lib/auth/index.ts | 4 ++-- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/mobile/src/common/hooks/useTabBarConfig.ts b/packages/mobile/src/common/hooks/useTabBarConfig.ts index eee06d2d..9e600c1e 100644 --- a/packages/mobile/src/common/hooks/useTabBarConfig.ts +++ b/packages/mobile/src/common/hooks/useTabBarConfig.ts @@ -107,6 +107,6 @@ export function useTabBarConfig(): { tabConfigLoading: fetching, fancyTab, shownTabs, - forceAll: data?.me.data?.linkblue === "demo-user", + forceAll: data?.me?.linkblue === "demo-user", }; } diff --git a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx index ce0c4547..570e5507 100644 --- a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx +++ b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx @@ -65,14 +65,14 @@ export function TriviaCrack() { ); const { stationOrder, moraleTeamNumber } = useMemo(() => { - const value = JSON.parse(option.value || "{}") as unknown; + const value = JSON.parse(option?.value || "{}") as unknown; let stationOrder: [number, number, number, number, number, number] | null = null; let moraleTeamNumber: number | undefined; if (typeof value === "object" && value !== null) { - if ((data?.me.data?.teams.length ?? 0) > 0) { + if ((data?.me?.teams.length ?? 0) > 0) { const moraleTeams = - data?.me.data?.teams.filter( + data?.me?.teams.filter( (team) => team.team.type === TeamType.Morale ) ?? []; if (moraleTeams[0]?.team.name.startsWith("Morale Team")) { @@ -110,7 +110,7 @@ export function TriviaCrack() { } } return { stationOrder, moraleTeamNumber }; - }, [data?.me.data?.teams, option.value]); + }, [data?.me?.teams, option?.value]); useEffect(() => { if (stationOrder && spins == null) { diff --git a/packages/mobile/src/context/auth.tsx b/packages/mobile/src/context/auth.tsx index cdff846e..475f8bf3 100644 --- a/packages/mobile/src/context/auth.tsx +++ b/packages/mobile/src/context/auth.tsx @@ -52,7 +52,7 @@ export function AuthStateProvider({ children }: { children: ReactNode }) { loggedIn: data?.loginState.loggedIn, authSource: data?.loginState.authSource, role: data?.loginState.dbRole, - userUuid: data?.me.data?.id, + userUuid: data?.me?.id, }, tags: ["graphql"], }); @@ -62,7 +62,7 @@ export function AuthStateProvider({ children }: { children: ReactNode }) { return ( { profileScreenAuthFragment={ rootScreenData?.loginState ?? null } - profileScreenUserFragment={rootScreenData?.me.data ?? null} + profileScreenUserFragment={rootScreenData?.me ?? null} /> )} diff --git a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx index 36321489..2f69c612 100644 --- a/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx +++ b/packages/mobile/src/navigation/root/tab/spirit/SpiritStack.tsx @@ -101,9 +101,7 @@ const SpiritScreen = () => { {() => ( refresh({ requestPolicy: "network-only" })} @@ -114,8 +112,8 @@ const SpiritScreen = () => { {() => ( diff --git a/packages/server/src/lib/auth/index.ts b/packages/server/src/lib/auth/index.ts index ce6ef284..31b28188 100644 --- a/packages/server/src/lib/auth/index.ts +++ b/packages/server/src/lib/auth/index.ts @@ -1,7 +1,7 @@ import type { JwtPayload, UserData } from "@ukdanceblue/common"; import { AuthSource } from "@ukdanceblue/common"; -import type { Request } from "express"; import jsonwebtoken from "jsonwebtoken"; +import type { Request } from "koa"; import { jwtSecret } from "../../environment.js"; @@ -97,7 +97,7 @@ export function tokenFromRequest( try { // Prefer cookie let jsonWebToken: string | undefined = undefined; - const cookies = req.cookies as unknown; + const cookies = req.ctx.cookies as unknown; if ( typeof cookies === "object" && cookies && From ccc47869cc6fcedbbd547006c70133d072bef269 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:11:13 +0000 Subject: [PATCH 139/153] Remove duplicate index file --- .../mobile/src/navigation/root/tab/InfoScreen/index.tsx | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 packages/mobile/src/navigation/root/tab/InfoScreen/index.tsx diff --git a/packages/mobile/src/navigation/root/tab/InfoScreen/index.tsx b/packages/mobile/src/navigation/root/tab/InfoScreen/index.tsx deleted file mode 100644 index fbdfe414..00000000 --- a/packages/mobile/src/navigation/root/tab/InfoScreen/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -// Allow importing from the parent folder rather than individual files -// For example you can do: *import { EventScreen } from '../EventScreen'* -// Instead of: *import { EventScreen } from '../EventScreen/EventScreen'* - - -export { default } from "./InfoScreen"; From 30c580d8231ffd09c6529e75591bb4888257aecf Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:28:19 +0000 Subject: [PATCH 140/153] Add import aliases to server --- packages/server/package.json | 12 +++++++ packages/server/src/environment.ts | 2 +- packages/server/src/index.ts | 4 +-- .../server/src/jobs/NotificationScheduler.ts | 8 ++--- packages/server/src/jobs/fetchPushReceipts.ts | 4 +-- .../server/src/jobs/garbageCollectLogins.ts | 4 +-- packages/server/src/jobs/syncDbFunds.ts | 16 ++++----- packages/server/src/lib/demo.ts | 2 +- packages/server/src/lib/files/FileManager.ts | 2 +- packages/server/src/lib/graphqlSchema.ts | 34 +++++++++---------- .../notification/ExpoNotificationProvider.ts | 6 ++-- .../notification/ExpoPushReceiptHandler.ts | 4 +-- packages/server/src/prisma.ts | 4 +-- .../committee/CommitteeRepository.ts | 8 ++--- .../committee/committeeRepositoryUtils.ts | 2 +- .../configuration/ConfigurationRepository.ts | 2 +- .../configurationRepositoryUtils.ts | 2 +- .../repositories/device/DeviceRepository.ts | 8 ++--- .../device/deviceRepositoryUtils.ts | 2 +- .../src/repositories/event/EventRepository.ts | 2 +- .../event/eventRepositoryUtils.ts | 2 +- .../fundraising/DBFundsRepository.ts | 10 +++--- .../fundraising/FundraisingRepository.ts | 10 +++--- .../fundraisingEntryRepositoryUtils.ts | 4 +-- .../src/repositories/image/ImageRepository.ts | 2 +- .../image/imageModelToResource.ts | 4 +-- .../image/imageRepositoryUtils.ts | 2 +- .../marathon/MarathonRepository.ts | 4 +-- .../marathon/marathonRepositoryUtils.ts | 2 +- .../marathonHour/MarathonHourRepository.ts | 2 +- .../marathonHourRepositoryUtils.ts | 2 +- .../membership/MembershipRepository.ts | 4 +-- .../membership/membershipRepositoryUtils.ts | 2 +- .../notification/NotificationRepository.ts | 2 +- .../notificationRepositoryUtils.ts | 2 +- .../NotificationDeliveryRepository.ts | 2 +- .../notificationDeliveryRepositoryUtils.ts | 2 +- .../repositories/person/PersonRepository.ts | 9 ++--- .../person/personRepositoryUtils.ts | 4 +-- .../pointEntry/PointEntryRepository.ts | 10 +++--- .../PointOpportunityRepository.ts | 2 +- .../pointOpportunityRepositoryUtils.ts | 2 +- packages/server/src/repositories/shared.ts | 10 +++--- .../src/repositories/team/TeamRepository.ts | 2 +- .../repositories/team/teamRepositoryUtils.ts | 2 +- .../src/resolvers/AdministrationResolver.ts | 2 +- .../src/resolvers/ConfigurationResolver.ts | 6 ++-- .../server/src/resolvers/DeviceResolver.ts | 14 ++++---- .../server/src/resolvers/EventResolver.ts | 12 +++---- packages/server/src/resolvers/FeedResolver.ts | 8 ++--- .../FundraisingAssignmentResolver.ts | 12 +++---- .../src/resolvers/FundraisingEntryResolver.ts | 12 +++---- .../server/src/resolvers/ImageResolver.ts | 12 +++---- .../src/resolvers/MarathonHourResolver.ts | 4 +-- .../server/src/resolvers/MarathonResolver.ts | 12 +++---- .../src/resolvers/MembershipResolver.ts | 10 +++--- packages/server/src/resolvers/NodeResolver.ts | 2 +- .../src/resolvers/NotificationResolver.ts | 14 ++++---- .../server/src/resolvers/PersonResolver.ts | 24 ++++++------- .../src/resolvers/PointEntryResolver.ts | 16 ++++----- .../src/resolvers/PointOpportunityResolver.ts | 6 ++-- packages/server/src/resolvers/TeamResolver.ts | 18 +++++----- packages/server/src/resolvers/context.ts | 12 +++---- .../server/src/routes/api/auth/anonymous.ts | 2 +- packages/server/src/routes/api/auth/demo.ts | 4 +-- packages/server/src/routes/api/auth/login.ts | 2 +- .../src/routes/api/auth/oidcCallback.ts | 8 ++--- .../src/routes/api/events/upcomingEvents.ts | 6 ++-- packages/server/src/routes/api/file/index.ts | 4 +-- .../server/src/routes/api/upload/index.ts | 8 ++--- packages/server/src/seed.ts | 6 ++-- packages/server/src/server.ts | 12 +++---- packages/server/src/types.d.ts | 2 +- packages/server/tsconfig.json | 14 +++++++- 74 files changed, 258 insertions(+), 233 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 610e5a2a..e2b82459 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -84,5 +84,17 @@ "prisma": { "seed": "node ./dist/seed.js" }, + "imports": { + "#auth/*.js": "./dist/lib/auth/*.js", + "#error/*.js": "./dist/lib/error/*.js", + "#files/*.js": "./dist/lib/files/*.js", + "#logging/*.js": "./dist/lib/logging/*.js", + "#notification/*.js": "./dist/lib/notification/*.js", + "#lib/*.js": "./dist/lib/*.js", + "#jobs/*.js": "./dist/jobs/*.js", + "#repositories/*.js": "./dist/repositories/*.js", + "#resolvers/*.js": "./dist/resolvers/*.js", + "#routes/*.js": "./dist/routes/*.js" + }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781" } diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index b6543d1d..42b4e88d 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -5,7 +5,7 @@ import dotenv from "dotenv"; import { Expo } from "expo-server-sdk"; import { Container, Token } from "typedi"; -import type { SyslogLevels } from "./lib/logging/standardLogging.js"; +import type { SyslogLevels } from "#logging/standardLogging.js"; dotenv.config(); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 646532f1..eb579736 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,4 +1,4 @@ -import { logger } from "./lib/logging/logger.js"; +import { logger } from "#logging/logger.js"; import "reflect-metadata"; @@ -37,4 +37,4 @@ logger.info("API started"); logger.info("DanceBlue Server Started"); // Start any manual cron jobs -await import("./jobs/index.js"); +await import("#jobs/index.js"); diff --git a/packages/server/src/jobs/NotificationScheduler.ts b/packages/server/src/jobs/NotificationScheduler.ts index 89703ef6..abc2716f 100644 --- a/packages/server/src/jobs/NotificationScheduler.ts +++ b/packages/server/src/jobs/NotificationScheduler.ts @@ -2,10 +2,10 @@ import type { Notification } from "@prisma/client"; import Cron, { scheduledJobs } from "croner"; import { Inject, Service } from "typedi"; -import { logger } from "../lib/logging/standardLogging.js"; -import { ExpoNotificationProvider } from "../lib/notification/ExpoNotificationProvider.js"; -import * as NotificationProviderJs from "../lib/notification/NotificationProvider.js"; -import { NotificationRepository } from "../repositories/notification/NotificationRepository.js"; +import { logger } from "#logging/standardLogging.js"; +import { ExpoNotificationProvider } from "#notification/ExpoNotificationProvider.js"; +import * as NotificationProviderJs from "#notification/NotificationProvider.js"; +import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; function scheduleId(notificationUuid: string) { return `scheduled-notification:${notificationUuid}`; diff --git a/packages/server/src/jobs/fetchPushReceipts.ts b/packages/server/src/jobs/fetchPushReceipts.ts index 89af1d51..53ee64b8 100644 --- a/packages/server/src/jobs/fetchPushReceipts.ts +++ b/packages/server/src/jobs/fetchPushReceipts.ts @@ -1,8 +1,8 @@ import Cron from "croner"; import { Container } from "typedi"; -import { logger } from "../lib/logging/standardLogging.js"; -import { ExpoPushReceiptHandler } from "../lib/notification/ExpoPushReceiptHandler.js"; +import { logger } from "#logging/standardLogging.js"; +import { ExpoPushReceiptHandler } from "#notification/ExpoPushReceiptHandler.js"; export const fetchPushReceipts = new Cron( "0 */8 * * * *", diff --git a/packages/server/src/jobs/garbageCollectLogins.ts b/packages/server/src/jobs/garbageCollectLogins.ts index 04d20281..e2d70486 100644 --- a/packages/server/src/jobs/garbageCollectLogins.ts +++ b/packages/server/src/jobs/garbageCollectLogins.ts @@ -1,8 +1,8 @@ import Cron from "croner"; import { Container } from "typedi"; -import { logger } from "../lib/logging/standardLogging.js"; -import { LoginFlowSessionRepository } from "../repositories/LoginFlowSession.js"; +import { logger } from "#logging/standardLogging.js"; +import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; export const garbageCollectLoginFlowSessions = new Cron( "0 0 */6 * * *", diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index 6d7483eb..da8fc272 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -3,17 +3,17 @@ import Cron from "croner"; import { Err, None, Ok, type Result } from "ts-results-es"; import { Container } from "typedi"; -import { CompositeError } from "../lib/error/composite.js"; -import type { NotFoundError } from "../lib/error/direct.js"; -import { toBasicError } from "../lib/error/error.js"; -import type { PrismaError } from "../lib/error/prisma.js"; +import { CompositeError } from "#error/composite.js"; +import type { NotFoundError } from "#error/direct.js"; +import { toBasicError } from "#error/error.js"; +import type { PrismaError } from "#error/prisma.js"; import { DBFundsFundraisingProvider, type DBFundsFundraisingProviderError, -} from "../lib/fundraising/DbFundsProvider.js"; -import { logger } from "../lib/logging/standardLogging.js"; -import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; -import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; +} from "#lib/fundraising/DbFundsProvider.js"; +import { logger } from "#logging/standardLogging.js"; +import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; +import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; type DoSyncError = | NotFoundError diff --git a/packages/server/src/lib/demo.ts b/packages/server/src/lib/demo.ts index 3f22faf1..3eea2a64 100644 --- a/packages/server/src/lib/demo.ts +++ b/packages/server/src/lib/demo.ts @@ -1,6 +1,6 @@ import { Container } from "typedi"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; export async function getOrMakeDemoUser() { return Container.get(PersonRepository).getDemoUser(); diff --git a/packages/server/src/lib/files/FileManager.ts b/packages/server/src/lib/files/FileManager.ts index 6e733bf7..ed5ee64b 100644 --- a/packages/server/src/lib/files/FileManager.ts +++ b/packages/server/src/lib/files/FileManager.ts @@ -3,8 +3,8 @@ import { MIMEType } from "util"; import type { File } from "@prisma/client"; import { Service } from "typedi"; +import { FileRepository } from "#repositories/file/fileRepository.js"; import { serveOrigin } from "../../environment.js"; -import { FileRepository } from "../../repositories/file/fileRepository.js"; import { logger } from "../logging/standardLogging.js"; import { LocalStorageProvider } from "./storage/LocalStorageProvider.js"; diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index ef11ff77..6c2ecc45 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -5,26 +5,26 @@ import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; -import { ConfigurationResolver } from "../resolvers/ConfigurationResolver.js"; -import { DeviceResolver } from "../resolvers/DeviceResolver.js"; -import { EventResolver } from "../resolvers/EventResolver.js"; -import { FeedResolver } from "../resolvers/FeedResolver.js"; -import { FundraisingAssignmentResolver } from "../resolvers/FundraisingAssignmentResolver.js"; -import { FundraisingEntryResolver } from "../resolvers/FundraisingEntryResolver.js"; -import { ImageResolver } from "../resolvers/ImageResolver.js"; -import { LoginStateResolver } from "../resolvers/LoginState.js"; -import { MarathonHourResolver } from "../resolvers/MarathonHourResolver.js"; -import { MarathonResolver } from "../resolvers/MarathonResolver.js"; -import { MembershipResolver } from "../resolvers/MembershipResolver.js"; -import { NodeResolver } from "../resolvers/NodeResolver.js"; +import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; +import { DeviceResolver } from "#resolvers/DeviceResolver.js"; +import { EventResolver } from "#resolvers/EventResolver.js"; +import { FeedResolver } from "#resolvers/FeedResolver.js"; +import { FundraisingAssignmentResolver } from "#resolvers/FundraisingAssignmentResolver.js"; +import { FundraisingEntryResolver } from "#resolvers/FundraisingEntryResolver.js"; +import { ImageResolver } from "#resolvers/ImageResolver.js"; +import { LoginStateResolver } from "#resolvers/LoginState.js"; +import { MarathonHourResolver } from "#resolvers/MarathonHourResolver.js"; +import { MarathonResolver } from "#resolvers/MarathonResolver.js"; +import { MembershipResolver } from "#resolvers/MembershipResolver.js"; +import { NodeResolver } from "#resolvers/NodeResolver.js"; import { NotificationDeliveryResolver, NotificationResolver, -} from "../resolvers/NotificationResolver.js"; -import { PersonResolver } from "../resolvers/PersonResolver.js"; -import { PointEntryResolver } from "../resolvers/PointEntryResolver.js"; -import { PointOpportunityResolver } from "../resolvers/PointOpportunityResolver.js"; -import { TeamResolver } from "../resolvers/TeamResolver.js"; +} from "#resolvers/NotificationResolver.js"; +import { PersonResolver } from "#resolvers/PersonResolver.js"; +import { PointEntryResolver } from "#resolvers/PointEntryResolver.js"; +import { PointOpportunityResolver } from "#resolvers/PointOpportunityResolver.js"; +import { TeamResolver } from "#resolvers/TeamResolver.js"; import { ConcreteError, toBasicError } from "./error/error.js"; import { CatchableConcreteError } from "./formatError.js"; diff --git a/packages/server/src/lib/notification/ExpoNotificationProvider.ts b/packages/server/src/lib/notification/ExpoNotificationProvider.ts index f7f9ab17..55adc631 100644 --- a/packages/server/src/lib/notification/ExpoNotificationProvider.ts +++ b/packages/server/src/lib/notification/ExpoNotificationProvider.ts @@ -9,10 +9,10 @@ import { Expo } from "expo-server-sdk"; import { DateTime } from "luxon"; import { Service } from "typedi"; +import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; +import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; +import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; import { isDevelopment } from "../../environment.js"; -import { DeviceRepository } from "../../repositories/device/DeviceRepository.js"; -import { NotificationRepository } from "../../repositories/notification/NotificationRepository.js"; -import { NotificationDeliveryRepository } from "../../repositories/notificationDelivery/NotificationDeliveryRepository.js"; import { logger } from "../logging/standardLogging.js"; import type { diff --git a/packages/server/src/lib/notification/ExpoPushReceiptHandler.ts b/packages/server/src/lib/notification/ExpoPushReceiptHandler.ts index f1863b5e..bc0863d6 100644 --- a/packages/server/src/lib/notification/ExpoPushReceiptHandler.ts +++ b/packages/server/src/lib/notification/ExpoPushReceiptHandler.ts @@ -3,8 +3,8 @@ import type { ExpoPushReceipt } from "expo-server-sdk"; import { Expo } from "expo-server-sdk"; import { Service } from "typedi"; -import { DeviceRepository } from "../../repositories/device/DeviceRepository.js"; -import { NotificationDeliveryRepository } from "../../repositories/notificationDelivery/NotificationDeliveryRepository.js"; +import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; +import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; @Service() export class ExpoPushReceiptHandler { diff --git a/packages/server/src/prisma.ts b/packages/server/src/prisma.ts index 5c162bc7..4b53ae02 100644 --- a/packages/server/src/prisma.ts +++ b/packages/server/src/prisma.ts @@ -2,8 +2,8 @@ import { PrismaClient } from "@prisma/client"; import { DetailedError, ErrorCode } from "@ukdanceblue/common"; import { Container } from "typedi"; -import { sqlLogger } from "./lib/logging/sqlLogging.js"; -import { logger } from "./lib/logging/standardLogging.js"; +import { sqlLogger } from "#logging/sqlLogging.js"; +import { logger } from "#logging/standardLogging.js"; export const prisma = new PrismaClient({ log: [ diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index 4ba9fdff..6dda0e0e 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -7,10 +7,10 @@ import { import { Err, None, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { CompositeError } from "../../lib/error/composite.js"; -import { InvariantError, NotFoundError } from "../../lib/error/direct.js"; -import { toBasicError } from "../../lib/error/error.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { CompositeError } from "#error/composite.js"; +import { InvariantError, NotFoundError } from "#error/direct.js"; +import { toBasicError } from "#error/error.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { MembershipRepository } from "../membership/MembershipRepository.js"; diff --git a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts index 9b3d7fbc..c30ca9cf 100644 --- a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts +++ b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts @@ -4,7 +4,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, oneOfFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { CommitteeFilters } from "./CommitteeRepository.js"; diff --git a/packages/server/src/repositories/configuration/ConfigurationRepository.ts b/packages/server/src/repositories/configuration/ConfigurationRepository.ts index 2889e240..825c5c3a 100644 --- a/packages/server/src/repositories/configuration/ConfigurationRepository.ts +++ b/packages/server/src/repositories/configuration/ConfigurationRepository.ts @@ -3,7 +3,7 @@ import type { SortDirection } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { SimpleUniqueParam } from "../shared.js"; import { diff --git a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts index 71290bfb..173ff79c 100644 --- a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts +++ b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts @@ -4,7 +4,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { ConfigurationFilters } from "./ConfigurationRepository.js"; diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index adc2d609..cd492e24 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -4,10 +4,10 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "../../lib/error/direct.js"; -import { CatchableConcreteError } from "../../lib/formatError.js"; -import type { NotificationAudience } from "../../lib/notification/NotificationProvider.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { NotFoundError } from "#error/direct.js"; +import { CatchableConcreteError } from "#lib/formatError.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { NotificationAudience } from "#notification/NotificationProvider.js"; import { PersonRepository } from "../person/PersonRepository.js"; import { RepositoryError } from "../shared.js"; diff --git a/packages/server/src/repositories/device/deviceRepositoryUtils.ts b/packages/server/src/repositories/device/deviceRepositoryUtils.ts index d251ea8f..b98b2d58 100644 --- a/packages/server/src/repositories/device/deviceRepositoryUtils.ts +++ b/packages/server/src/repositories/device/deviceRepositoryUtils.ts @@ -4,7 +4,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { DeviceFilters } from "./DeviceRepository.js"; diff --git a/packages/server/src/repositories/event/EventRepository.ts b/packages/server/src/repositories/event/EventRepository.ts index c85f5fa4..ef0e40ef 100644 --- a/packages/server/src/repositories/event/EventRepository.ts +++ b/packages/server/src/repositories/event/EventRepository.ts @@ -2,7 +2,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildEventOrder, buildEventWhere } from "./eventRepositoryUtils.js"; diff --git a/packages/server/src/repositories/event/eventRepositoryUtils.ts b/packages/server/src/repositories/event/eventRepositoryUtils.ts index ecc6aed6..2b8721fa 100644 --- a/packages/server/src/repositories/event/eventRepositoryUtils.ts +++ b/packages/server/src/repositories/event/eventRepositoryUtils.ts @@ -5,7 +5,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { EventFilters, EventOrderKeys } from "./EventRepository.ts"; diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 87820a65..01827959 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -3,11 +3,11 @@ import { DateTime } from "luxon"; import { Err, None, Ok, Option, Result } from "ts-results-es"; import { Service } from "typedi"; -import { CompositeError } from "../../lib/error/composite.js"; -import { NotFoundError } from "../../lib/error/direct.js"; -import { BasicError } from "../../lib/error/error.js"; -import { PrismaError, SomePrismaError } from "../../lib/error/prisma.js"; -import { logger } from "../../lib/logging/standardLogging.js"; +import { CompositeError } from "#error/composite.js"; +import { NotFoundError } from "#error/direct.js"; +import { BasicError } from "#error/error.js"; +import { PrismaError, SomePrismaError } from "#error/prisma.js"; +import { logger } from "#logging/standardLogging.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index 10b3d401..e5b6728d 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -10,11 +10,11 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, None, Ok, Option, Result, Some } from "ts-results-es"; import { Service } from "typedi"; -import { ActionDeniedError } from "../../lib/error/control.js"; -import { NotFoundError } from "../../lib/error/direct.js"; -import { BasicError } from "../../lib/error/error.js"; -import { SomePrismaError } from "../../lib/error/prisma.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { ActionDeniedError } from "#error/control.js"; +import { NotFoundError } from "#error/direct.js"; +import { BasicError } from "#error/error.js"; +import { SomePrismaError } from "#error/prisma.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { UniquePersonParam } from "../person/PersonRepository.js"; import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index 5bfecde0..f2c5ef77 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -3,13 +3,13 @@ import { SortDirection } from "@ukdanceblue/common"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; -import { ActionDeniedError } from "../../lib/error/control.js"; +import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, numericFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { FundraisingEntryFilters, diff --git a/packages/server/src/repositories/image/ImageRepository.ts b/packages/server/src/repositories/image/ImageRepository.ts index 97319488..b059b4a9 100644 --- a/packages/server/src/repositories/image/ImageRepository.ts +++ b/packages/server/src/repositories/image/ImageRepository.ts @@ -2,7 +2,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildImageOrder, buildImageWhere } from "./imageRepositoryUtils.js"; diff --git a/packages/server/src/repositories/image/imageModelToResource.ts b/packages/server/src/repositories/image/imageModelToResource.ts index 9d02b706..b24ea651 100644 --- a/packages/server/src/repositories/image/imageModelToResource.ts +++ b/packages/server/src/repositories/image/imageModelToResource.ts @@ -1,8 +1,8 @@ import type { File, Image } from "@prisma/client"; import { ImageNode } from "@ukdanceblue/common"; -import type { FileManager } from "../../lib/files/FileManager.js"; -import { combineMimePartsToString } from "../../lib/files/mime.js"; +import type { FileManager } from "#files/FileManager.js"; +import { combineMimePartsToString } from "#files/mime.js"; export async function imageModelToResource( imageModel: Image, diff --git a/packages/server/src/repositories/image/imageRepositoryUtils.ts b/packages/server/src/repositories/image/imageRepositoryUtils.ts index 74ca6df9..39193821 100644 --- a/packages/server/src/repositories/image/imageRepositoryUtils.ts +++ b/packages/server/src/repositories/image/imageRepositoryUtils.ts @@ -5,7 +5,7 @@ import { dateFilterToPrisma, numericFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { ImageFilters } from "./ImageRepository.ts"; diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 44eb0e3b..fabbdc3e 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -3,8 +3,8 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "../../lib/error/direct.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { NotFoundError } from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, type RepositoryError } from "../shared.js"; import { diff --git a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts index aea9b9b2..b155acf4 100644 --- a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts +++ b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts @@ -4,7 +4,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, oneOfFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { MarathonFilters, diff --git a/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts b/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts index 35ced2f8..4741395f 100644 --- a/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts +++ b/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts @@ -2,7 +2,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildMarathonHourOrder, diff --git a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts index ba093a1d..55f15faf 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts @@ -5,7 +5,7 @@ import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { MarathonHourFilters, diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index e07e5c23..be3abaed 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -3,8 +3,8 @@ import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "../../lib/error/direct.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { NotFoundError } from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, type RepositoryError, diff --git a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts index 18dc2710..a73a365b 100644 --- a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts +++ b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts @@ -1,7 +1,7 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; -import { dateFilterToPrisma } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { dateFilterToPrisma } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { MembershipFilters } from "./MembershipRepository.ts"; diff --git a/packages/server/src/repositories/notification/NotificationRepository.ts b/packages/server/src/repositories/notification/NotificationRepository.ts index 740d65ad..b65a5c78 100644 --- a/packages/server/src/repositories/notification/NotificationRepository.ts +++ b/packages/server/src/repositories/notification/NotificationRepository.ts @@ -3,7 +3,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildNotificationOrder, diff --git a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts index a72b6b41..4f894fe3 100644 --- a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts +++ b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts @@ -5,7 +5,7 @@ import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { NotificationFilters, diff --git a/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts b/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts index 20fe7d2d..447b0301 100644 --- a/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts +++ b/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts @@ -4,7 +4,7 @@ import type { ExpoPushReceipt, ExpoPushTicket } from "expo-server-sdk"; import type { DateTime } from "luxon"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildNotificationDeliveryOrder, diff --git a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts index b7982d63..e00c36b1 100644 --- a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts +++ b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts @@ -4,7 +4,7 @@ import { SortDirection } from "@ukdanceblue/common"; import { dateFilterToPrisma, oneOfFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { NotificationDeliveryFilters, diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index b2b5a44c..88de6297 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -16,14 +16,13 @@ import { import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { findPersonForLogin } from "../../lib/auth/findPersonForLogin.js"; -import { ActionDeniedError } from "../../lib/error/control.js"; +import { ActionDeniedError } from "#error/control.js"; import { InvalidArgumentError, InvariantError, NotFoundError, -} from "../../lib/error/direct.js"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { handleRepositoryError, @@ -33,6 +32,8 @@ import { import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; +import { findPersonForLogin } from "#auth/findPersonForLogin.js"; + const personStringKeys = ["name", "email", "linkblue"] as const; type PersonStringKey = (typeof personStringKeys)[number]; diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index c64444fa..b8318243 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -3,11 +3,11 @@ import { SortDirection } from "@ukdanceblue/common"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; -import { ActionDeniedError } from "../../lib/error/control.js"; +import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { PersonFilters, PersonOrderKeys } from "./PersonRepository.js"; diff --git a/packages/server/src/repositories/pointEntry/PointEntryRepository.ts b/packages/server/src/repositories/pointEntry/PointEntryRepository.ts index eb0a4060..7f9205f3 100644 --- a/packages/server/src/repositories/pointEntry/PointEntryRepository.ts +++ b/packages/server/src/repositories/pointEntry/PointEntryRepository.ts @@ -2,7 +2,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildPointEntryOrder, @@ -145,14 +145,14 @@ export class PointEntryRepository { personParam === null ? { disconnect: true } : personParam === undefined - ? undefined - : { connect: personParam }, + ? undefined + : { connect: personParam }, pointOpportunity: opportunityParam === null ? { disconnect: true } : opportunityParam === undefined - ? undefined - : { connect: opportunityParam }, + ? undefined + : { connect: opportunityParam }, team: teamParam === undefined ? undefined : { connect: teamParam }, }, }); diff --git a/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts b/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts index 847f42ca..2893d7fa 100644 --- a/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts +++ b/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts @@ -3,7 +3,7 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { buildPointOpportunityOrder, diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts index 4a66a0b6..8ee59d55 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts @@ -5,7 +5,7 @@ import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { PointOpportunityFilters, diff --git a/packages/server/src/repositories/shared.ts b/packages/server/src/repositories/shared.ts index 4170f0d1..ee216399 100644 --- a/packages/server/src/repositories/shared.ts +++ b/packages/server/src/repositories/shared.ts @@ -1,10 +1,10 @@ import { Err } from "ts-results-es"; -import type { NotFoundError } from "../lib/error/direct.js"; -import type { BasicError } from "../lib/error/error.js"; -import { toBasicError } from "../lib/error/error.js"; -import type { SomePrismaError } from "../lib/error/prisma.js"; -import { toPrismaError } from "../lib/error/prisma.js"; +import type { NotFoundError } from "#error/direct.js"; +import type { BasicError } from "#error/error.js"; +import { toBasicError } from "#error/error.js"; +import type { SomePrismaError } from "#error/prisma.js"; +import { toPrismaError } from "#error/prisma.js"; export type SimpleUniqueParam = { id: number } | { uuid: string }; export type RepositoryError = SomePrismaError | BasicError | NotFoundError; diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index 8aef1799..cc23de71 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -7,7 +7,7 @@ import type { import { TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index 8e3726c7..c045ad50 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -6,7 +6,7 @@ import { numericFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, -} from "../../lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { TeamFilters, TeamOrderKeys } from "./TeamRepository.ts"; diff --git a/packages/server/src/resolvers/AdministrationResolver.ts b/packages/server/src/resolvers/AdministrationResolver.ts index 2b3e7f1e..6996efbd 100644 --- a/packages/server/src/resolvers/AdministrationResolver.ts +++ b/packages/server/src/resolvers/AdministrationResolver.ts @@ -4,8 +4,8 @@ import { join } from "path"; import { AccessControl, AccessLevel } from "@ukdanceblue/common"; import { FieldResolver, ObjectType, Query, Resolver } from "type-graphql"; +import { auditLoggerFileName } from "#logging/auditLogging.js"; import { logDir } from "../environment.js"; -import { auditLoggerFileName } from "../lib/logging/auditLogging.js"; @ObjectType() export class Administration { diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index e49a0ab7..a3e9a303 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -21,9 +21,9 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { auditLogger } from "../lib/logging/auditLogging.js"; -import { ConfigurationRepository } from "../repositories/configuration/ConfigurationRepository.js"; -import { configurationModelToResource } from "../repositories/configuration/configurationModelToResource.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; +import { configurationModelToResource } from "#repositories/configuration/configurationModelToResource.js"; import { AbstractGraphQLArrayOkResponse, diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 8eb902ce..0948ced1 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -25,13 +25,13 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; -import { auditLogger } from "../lib/logging/auditLogging.js"; -import { DeviceRepository } from "../repositories/device/DeviceRepository.js"; -import { deviceModelToResource } from "../repositories/device/deviceModelToResource.js"; -import { notificationDeliveryModelToResource } from "../repositories/notificationDelivery/notificationDeliveryModelToResource.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; +import { ConcreteResult } from "#error/result.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; +import { deviceModelToResource } from "#repositories/device/deviceModelToResource.js"; +import { notificationDeliveryModelToResource } from "#repositories/notificationDelivery/notificationDeliveryModelToResource.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; import { AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index f791295b..eef20692 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -27,15 +27,15 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { FileManager } from "../lib/files/FileManager.js"; -import { auditLogger } from "../lib/logging/auditLogging.js"; -import { EventRepository } from "../repositories/event/EventRepository.js"; +import { FileManager } from "#files/FileManager.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { EventRepository } from "#repositories/event/EventRepository.js"; import { eventModelToResource, eventOccurrenceModelToResource, -} from "../repositories/event/eventModelToResource.js"; -import { EventImagesRepository } from "../repositories/event/images/EventImagesRepository.js"; -import { imageModelToResource } from "../repositories/image/imageModelToResource.js"; +} from "#repositories/event/eventModelToResource.js"; +import { EventImagesRepository } from "#repositories/event/images/EventImagesRepository.js"; +import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; import { AbstractGraphQLCreatedResponse, diff --git a/packages/server/src/resolvers/FeedResolver.ts b/packages/server/src/resolvers/FeedResolver.ts index cb736d13..e17de7fb 100644 --- a/packages/server/src/resolvers/FeedResolver.ts +++ b/packages/server/src/resolvers/FeedResolver.ts @@ -17,10 +17,10 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { FileManager } from "../lib/files/FileManager.js"; -import { FeedRepository } from "../repositories/feed/FeedRepository.js"; -import { feedItemModelToResource } from "../repositories/feed/feedModelToResource.js"; -import { imageModelToResource } from "../repositories/image/imageModelToResource.js"; +import { FileManager } from "#files/FileManager.js"; +import { FeedRepository } from "#repositories/feed/FeedRepository.js"; +import { feedItemModelToResource } from "#repositories/feed/feedModelToResource.js"; +import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; @InputType() export class CreateFeedInput { diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 21c9e426..e2fa28b6 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -22,12 +22,12 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; -import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; -import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; +import { ConcreteResult } from "#error/result.js"; +import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; +import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; import { globalFundraisingAccessParam } from "./FundraisingEntryResolver.js"; diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 7fbe61d0..3715a8ab 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -24,12 +24,12 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; -import { CatchableConcreteError } from "../lib/formatError.js"; -import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; -import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; -import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; +import { ConcreteResult } from "#error/result.js"; +import { CatchableConcreteError } from "#lib/formatError.js"; +import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; +import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; +import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index 4db13aca..20b89e92 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -26,12 +26,12 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { FileManager } from "../lib/files/FileManager.js"; -import { auditLogger } from "../lib/logging/auditLogging.js"; -import { logger } from "../lib/logging/standardLogging.js"; -import { generateThumbHash } from "../lib/thumbHash.js"; -import { ImageRepository } from "../repositories/image/ImageRepository.js"; -import { imageModelToResource } from "../repositories/image/imageModelToResource.js"; +import { FileManager } from "#files/FileManager.js"; +import { generateThumbHash } from "#lib/thumbHash.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { logger } from "#logging/standardLogging.js"; +import { ImageRepository } from "#repositories/image/ImageRepository.js"; +import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; import { AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index 16b97f13..58e357bd 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -23,8 +23,8 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { MarathonHourRepository } from "../repositories/marathonHour/MarathonHourRepository.js"; -import { marathonHourModelToResource } from "../repositories/marathonHour/marathonHourModelToResource.js"; +import { MarathonHourRepository } from "#repositories/marathonHour/MarathonHourRepository.js"; +import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 8c51109e..4a5109c8 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -24,12 +24,12 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; -import { CommitteeRepository } from "../repositories/committee/CommitteeRepository.js"; -import { MarathonRepository } from "../repositories/marathon/MarathonRepository.js"; -import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; -import { marathonHourModelToResource } from "../repositories/marathonHour/marathonHourModelToResource.js"; -import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; +import { ConcreteResult } from "#error/result.js"; +import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; +import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; +import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; +import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; +import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index 5c7930a7..c10ac41b 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -2,11 +2,11 @@ import { MembershipNode, PersonNode, TeamNode } from "@ukdanceblue/common"; import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; -import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; -import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; +import { ConcreteResult } from "#error/result.js"; +import { MembershipRepository } from "#repositories/membership/MembershipRepository.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; +import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; @Resolver(() => MembershipNode) @Service() export class MembershipResolver { diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 00230300..0df93a3c 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -20,7 +20,7 @@ import { Ok } from "ts-results-es"; import { Arg, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "../lib/error/result.js"; +import { ConcreteResult } from "#error/result.js"; import { ConfigurationResolver } from "./ConfigurationResolver.js"; import { DeviceResolver } from "./DeviceResolver.js"; diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index ed8feeba..0445839e 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -28,13 +28,13 @@ import { } from "type-graphql"; import { Inject, Service } from "typedi"; -import { NotificationScheduler } from "../jobs/NotificationScheduler.js"; -import { ExpoNotificationProvider } from "../lib/notification/ExpoNotificationProvider.js"; -import * as NotificationProviderJs from "../lib/notification/NotificationProvider.js"; -import { NotificationRepository } from "../repositories/notification/NotificationRepository.js"; -import { notificationModelToResource } from "../repositories/notification/notificationModelToResource.js"; -import { NotificationDeliveryRepository } from "../repositories/notificationDelivery/NotificationDeliveryRepository.js"; -import { notificationDeliveryModelToResource } from "../repositories/notificationDelivery/notificationDeliveryModelToResource.js"; +import { NotificationScheduler } from "#jobs/NotificationScheduler.js"; +import { ExpoNotificationProvider } from "#notification/ExpoNotificationProvider.js"; +import * as NotificationProviderJs from "#notification/NotificationProvider.js"; +import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; +import { notificationModelToResource } from "#repositories/notification/notificationModelToResource.js"; +import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; +import { notificationDeliveryModelToResource } from "#repositories/notificationDelivery/notificationDeliveryModelToResource.js"; import { AbstractGraphQLCreatedResponse, diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 3162d438..e7f18ed6 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -32,21 +32,21 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteError } from "../lib/error/error.js"; -import { ConcreteResult } from "../lib/error/result.js"; -import { CatchableConcreteError } from "../lib/formatError.js"; -import { auditLogger } from "../lib/logging/auditLogging.js"; -import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; -import { fundraisingAssignmentModelToNode } from "../repositories/fundraising/fundraisingAssignmentModelToNode.js"; -import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; -import { MembershipRepository } from "../repositories/membership/MembershipRepository.js"; +import { ConcreteError } from "#error/error.js"; +import { ConcreteResult } from "#error/result.js"; +import { CatchableConcreteError } from "#lib/formatError.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; +import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; +import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; +import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; +import { MembershipRepository } from "#repositories/membership/MembershipRepository.js"; import { committeeMembershipModelToResource, membershipModelToResource, -} from "../repositories/membership/membershipModelToResource.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; +} from "#repositories/membership/membershipModelToResource.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 09aa3b25..3c17eaf3 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -27,14 +27,14 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { NotFoundError } from "../lib/error/direct.js"; -import { ConcreteResult } from "../lib/error/result.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; -import { PointEntryRepository } from "../repositories/pointEntry/PointEntryRepository.js"; -import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; -import { pointOpportunityModelToResource } from "../repositories/pointOpportunity/pointOpportunityModelToResource.js"; -import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; +import { NotFoundError } from "#error/direct.js"; +import { ConcreteResult } from "#error/result.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; +import { PointEntryRepository } from "#repositories/pointEntry/PointEntryRepository.js"; +import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; +import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; +import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; import { AbstractGraphQLCreatedResponse, diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index 7550c1e4..0da2d1dd 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -26,9 +26,9 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { eventModelToResource } from "../repositories/event/eventModelToResource.js"; -import { PointOpportunityRepository } from "../repositories/pointOpportunity/PointOpportunityRepository.js"; -import { pointOpportunityModelToResource } from "../repositories/pointOpportunity/pointOpportunityModelToResource.js"; +import { eventModelToResource } from "#repositories/event/eventModelToResource.js"; +import { PointOpportunityRepository } from "#repositories/pointOpportunity/PointOpportunityRepository.js"; +import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; import { AbstractGraphQLCreatedResponse, diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 41d9d1dd..b4edcd0b 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -35,15 +35,15 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { CatchableConcreteError } from "../lib/formatError.js"; -import { DBFundsRepository } from "../repositories/fundraising/DBFundsRepository.js"; -import { FundraisingEntryRepository } from "../repositories/fundraising/FundraisingRepository.js"; -import { fundraisingEntryModelToNode } from "../repositories/fundraising/fundraisingEntryModelToNode.js"; -import { marathonModelToResource } from "../repositories/marathon/marathonModelToResource.js"; -import { membershipModelToResource } from "../repositories/membership/membershipModelToResource.js"; -import { pointEntryModelToResource } from "../repositories/pointEntry/pointEntryModelToResource.js"; -import { TeamRepository } from "../repositories/team/TeamRepository.js"; -import { teamModelToResource } from "../repositories/team/teamModelToResource.js"; +import { CatchableConcreteError } from "#lib/formatError.js"; +import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; +import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; +import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; +import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; +import { membershipModelToResource } from "#repositories/membership/membershipModelToResource.js"; +import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; +import { TeamRepository } from "#repositories/team/TeamRepository.js"; +import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; import { AbstractGraphQLCreatedResponse, diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 21880c4d..71d34541 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -16,12 +16,12 @@ import type { DefaultState } from "koa"; import { Ok } from "ts-results-es"; import { Container } from "typedi"; -import { defaultAuthorization, parseUserJwt } from "../lib/auth/index.js"; -import { NotFoundError } from "../lib/error/direct.js"; -import type { ConcreteResult } from "../lib/error/result.js"; -import { logger } from "../lib/logging/logger.js"; -import { PersonRepository } from "../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../repositories/person/personModelToResource.js"; +import { defaultAuthorization, parseUserJwt } from "#auth/index.js"; +import { NotFoundError } from "#error/direct.js"; +import type { ConcreteResult } from "#error/result.js"; +import { logger } from "#logging/logger.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; export interface GraphQLContext extends AuthorizationContext { contextErrors: string[]; diff --git a/packages/server/src/routes/api/auth/anonymous.ts b/packages/server/src/routes/api/auth/anonymous.ts index f6ec1f34..2c5acc10 100644 --- a/packages/server/src/routes/api/auth/anonymous.ts +++ b/packages/server/src/routes/api/auth/anonymous.ts @@ -2,7 +2,7 @@ import { AuthSource } from "@ukdanceblue/common"; import type { Context } from "koa"; import { DateTime } from "luxon"; -import { makeUserJwt } from "../../../lib/auth/index.js"; +import { makeUserJwt } from "#auth/index.js"; export const anonymousLogin = (ctx: Context) => { let redirectTo = "/"; diff --git a/packages/server/src/routes/api/auth/demo.ts b/packages/server/src/routes/api/auth/demo.ts index 9cb1244a..dfb157a1 100644 --- a/packages/server/src/routes/api/auth/demo.ts +++ b/packages/server/src/routes/api/auth/demo.ts @@ -2,8 +2,8 @@ import { AuthSource } from "@ukdanceblue/common"; import type { Context } from "koa"; import { DateTime } from "luxon"; -import { makeUserJwt } from "../../../lib/auth/index.js"; -import { getOrMakeDemoUser } from "../../../lib/demo.js"; +import { makeUserJwt } from "#auth/index.js"; +import { getOrMakeDemoUser } from "#lib/demo.js"; export const demoLogin = async (ctx: Context) => { let redirectTo = "/"; diff --git a/packages/server/src/routes/api/auth/login.ts b/packages/server/src/routes/api/auth/login.ts index d351cafc..3258a010 100644 --- a/packages/server/src/routes/api/auth/login.ts +++ b/packages/server/src/routes/api/auth/login.ts @@ -2,7 +2,7 @@ import type { Context } from "koa"; import { generators } from "openid-client"; import { Container } from "typedi"; -import { LoginFlowSessionRepository } from "../../../repositories/LoginFlowSession.js"; +import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; import { makeOidcClient } from "./oidcClient.js"; diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index 362e27ba..38b93ef8 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -6,10 +6,10 @@ import type { Context } from "koa"; import { DateTime } from "luxon"; import { Container } from "typedi"; -import { makeUserJwt } from "../../../lib/auth/index.js"; -import { LoginFlowSessionRepository } from "../../../repositories/LoginFlowSession.js"; -import { PersonRepository } from "../../../repositories/person/PersonRepository.js"; -import { personModelToResource } from "../../../repositories/person/personModelToResource.js"; +import { makeUserJwt } from "#auth/index.js"; +import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { personModelToResource } from "#repositories/person/personModelToResource.js"; import { makeOidcClient } from "./oidcClient.js"; diff --git a/packages/server/src/routes/api/events/upcomingEvents.ts b/packages/server/src/routes/api/events/upcomingEvents.ts index ac37e8de..9b45ec7f 100644 --- a/packages/server/src/routes/api/events/upcomingEvents.ts +++ b/packages/server/src/routes/api/events/upcomingEvents.ts @@ -3,9 +3,9 @@ import { DateTime } from "luxon"; import type { NextFn } from "type-graphql"; import { Container } from "typedi"; -import { FileManager } from "../../../lib/files/FileManager.js"; -import { combineMimePartsToString } from "../../../lib/files/mime.js"; -import { EventRepository } from "../../../repositories/event/EventRepository.js"; +import { FileManager } from "#files/FileManager.js"; +import { combineMimePartsToString } from "#files/mime.js"; +import { EventRepository } from "#repositories/event/EventRepository.js"; const EMPTY_PNG_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NgAAIAAAUAAR4f7BQAAAAASUVORK5CYII="; diff --git a/packages/server/src/routes/api/file/index.ts b/packages/server/src/routes/api/file/index.ts index a323f0e5..62bef7c2 100644 --- a/packages/server/src/routes/api/file/index.ts +++ b/packages/server/src/routes/api/file/index.ts @@ -1,8 +1,8 @@ import Router from "@koa/router"; import { Container } from "typedi"; -import { FileManager } from "../../../lib/files/FileManager.js"; -import { combineMimePartsToString } from "../../../lib/files/mime.js"; +import { FileManager } from "#files/FileManager.js"; +import { combineMimePartsToString } from "#files/mime.js"; const fileRouter = new Router({ prefix: "/file" }); diff --git a/packages/server/src/routes/api/upload/index.ts b/packages/server/src/routes/api/upload/index.ts index 4c767464..0bae79bf 100644 --- a/packages/server/src/routes/api/upload/index.ts +++ b/packages/server/src/routes/api/upload/index.ts @@ -5,11 +5,11 @@ import type { File } from "@prisma/client"; import { koaBody } from "koa-body"; import { Container } from "typedi"; +import { FileManager } from "#files/FileManager.js"; +import { generateThumbHash } from "#lib/thumbHash.js"; +import { logger } from "#logging/standardLogging.js"; +import { ImageRepository } from "#repositories/image/ImageRepository.js"; import { maxFileSize } from "../../../environment.js"; -import { FileManager } from "../../../lib/files/FileManager.js"; -import { logger } from "../../../lib/logging/standardLogging.js"; -import { generateThumbHash } from "../../../lib/thumbHash.js"; -import { ImageRepository } from "../../../repositories/image/ImageRepository.js"; const uploadRouter = new Router({ prefix: "/upload" }).post( "/image/:uuid", diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index 5be2ba3b..846997fa 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -1,10 +1,10 @@ import { CommitteeIdentifier, CommitteeRole } from "@ukdanceblue/common"; import { Container } from "typedi"; +import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; +import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; +import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { isDevelopment } from "./environment.js"; -import { CommitteeRepository } from "./repositories/committee/CommitteeRepository.js"; -import { ConfigurationRepository } from "./repositories/configuration/ConfigurationRepository.js"; -import { PersonRepository } from "./repositories/person/PersonRepository.js"; if (!isDevelopment) { throw new Error("Seeding is only allowed in development mode"); diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 3983f56d..68c4b78f 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -13,17 +13,17 @@ import type { DefaultState } from "koa"; import Koa from "koa"; import { koaBody } from "koa-body"; +import { logger } from "#logging/logger.js"; +import type { GraphQLContext } from "#resolvers/context.js"; +import eventsApiRouter from "#routes/api/events/index.js"; +import fileRouter from "#routes/api/file/index.js"; +import healthCheckRouter from "#routes/api/healthcheck/index.js"; +import uploadRouter from "#routes/api/upload/index.js"; import { applicationHost, applicationPort, loggingLevel, } from "./environment.js"; -import { logger } from "./lib/logging/logger.js"; -import type { GraphQLContext } from "./resolvers/context.js"; -import eventsApiRouter from "./routes/api/events/index.js"; -import fileRouter from "./routes/api/file/index.js"; -import healthCheckRouter from "./routes/api/healthcheck/index.js"; -import uploadRouter from "./routes/api/upload/index.js"; const basicLoggingPlugin: ApolloServerPlugin = { requestDidStart(requestContext) { diff --git a/packages/server/src/types.d.ts b/packages/server/src/types.d.ts index 98668072..e7d1b3b3 100644 --- a/packages/server/src/types.d.ts +++ b/packages/server/src/types.d.ts @@ -1,4 +1,4 @@ -import { SyslogLevels } from "./lib/logging/standardLogging.ts"; +import { SyslogLevels } from "#logging/standardLogging.ts"; declare global { namespace NodeJS { diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index a781f7ab..6044f4a0 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -12,7 +12,19 @@ "allowJs": true, "checkJs": true, "emitDecoratorMetadata": true, - "experimentalDecorators": true + "experimentalDecorators": true, + "paths": { + "#auth/*": ["./src/lib/auth/*"], + "#error/*": ["./src/lib/error/*"], + "#files/*": ["./src/lib/files/*"], + "#logging/*": ["./src/lib/logging/*"], + "#notification/*": ["./src/lib/notification/*"], + "#lib/*": ["./src/lib/*"], + "#jobs/*": ["./src/jobs/*"], + "#repositories/*": ["./src/repositories/*"], + "#resolvers/*": ["./src/resolvers/*"], + "#routes/*": ["./src/routes/*"] + } }, "include": ["src"], "extends": "../../tsconfig.json" From 23c5a967530b9c9d1bd14e1074983c309aa35eec Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:36:03 +0000 Subject: [PATCH 141/153] Change import sort rules --- eslint/base.ts | 17 ++++++++++++---- eslint/out/base.js | 9 ++++----- packages/server/src/lib/files/FileManager.ts | 2 +- packages/server/src/lib/graphqlSchema.ts | 6 +++--- .../notification/ExpoNotificationProvider.ts | 8 ++++---- .../committee/CommitteeRepository.ts | 8 ++++---- .../committee/committeeRepositoryUtils.ts | 2 +- .../configuration/ConfigurationRepository.ts | 2 +- .../configurationRepositoryUtils.ts | 2 +- .../repositories/device/DeviceRepository.ts | 6 +++--- .../device/deviceRepositoryUtils.ts | 2 +- .../src/repositories/event/EventRepository.ts | 2 +- .../event/eventRepositoryUtils.ts | 2 +- .../fundraising/DBFundsRepository.ts | 6 +++--- .../fundraising/FundraisingRepository.ts | 12 +++++------ .../fundraisingEntryRepositoryUtils.ts | 8 ++++---- .../src/repositories/image/ImageRepository.ts | 2 +- .../image/imageRepositoryUtils.ts | 2 +- .../marathon/MarathonRepository.ts | 6 +++--- .../marathon/marathonRepositoryUtils.ts | 8 ++++---- .../marathonHour/MarathonHourRepository.ts | 4 ++-- .../marathonHourRepositoryUtils.ts | 8 ++++---- .../membership/MembershipRepository.ts | 4 ++-- .../membership/membershipRepositoryUtils.ts | 2 +- .../notification/NotificationRepository.ts | 3 +-- .../notificationRepositoryUtils.ts | 8 ++++---- .../NotificationDeliveryRepository.ts | 4 ++-- .../notificationDeliveryRepositoryUtils.ts | 8 ++++---- .../repositories/person/PersonRepository.ts | 14 ++++++------- .../person/personRepositoryUtils.ts | 2 +- .../pointEntry/PointEntryRepository.ts | 4 ++-- .../PointOpportunityRepository.ts | 4 ++-- .../pointOpportunityRepositoryUtils.ts | 8 ++++---- .../src/repositories/team/TeamRepository.ts | 2 +- .../repositories/team/teamRepositoryUtils.ts | 2 +- .../src/resolvers/AdministrationResolver.ts | 2 +- .../src/resolvers/ConfigurationResolver.ts | 8 ++++---- .../server/src/resolvers/DeviceResolver.ts | 8 ++++---- .../server/src/resolvers/EventResolver.ts | 10 +++++----- .../FundraisingAssignmentResolver.ts | 2 +- .../src/resolvers/FundraisingEntryResolver.ts | 2 +- .../server/src/resolvers/ImageResolver.ts | 8 ++++---- .../src/resolvers/MarathonHourResolver.ts | 2 +- .../server/src/resolvers/MarathonResolver.ts | 2 +- packages/server/src/resolvers/NodeResolver.ts | 2 +- .../src/resolvers/NotificationResolver.ts | 10 +++++----- .../server/src/resolvers/PersonResolver.ts | 14 ++++++------- .../src/resolvers/PointEntryResolver.ts | 10 +++++----- .../src/resolvers/PointOpportunityResolver.ts | 8 ++++---- packages/server/src/resolvers/TeamResolver.ts | 20 +++++++++---------- packages/server/src/routes/api/auth/login.ts | 2 +- .../src/routes/api/auth/oidcCallback.ts | 2 +- .../server/src/routes/api/upload/index.ts | 2 +- packages/server/src/seed.ts | 2 +- packages/server/src/server.ts | 10 +++++----- 55 files changed, 161 insertions(+), 154 deletions(-) diff --git a/eslint/base.ts b/eslint/base.ts index 397a1d86..4ecdc3f1 100644 --- a/eslint/base.ts +++ b/eslint/base.ts @@ -62,12 +62,21 @@ const rules: Linter.RulesRecord = { "import/order": [ "error", { - "groups": ["builtin", "external", "parent", "sibling", "index"], + "groups": [ + "index", + "sibling", + "parent", + "internal", + "external", + "builtin", + "object", + "type", + ], "pathGroups": [ { - pattern: "@custom-lib/**", - group: "external", - position: "after", + pattern: "#**", + group: "internal", + position: "before", }, ], "pathGroupsExcludedImportTypes": ["builtin"], diff --git a/eslint/out/base.js b/eslint/out/base.js index edd6abf5..ccbc6a03 100644 --- a/eslint/out/base.js +++ b/eslint/out/base.js @@ -60,19 +60,18 @@ const rules = { "import/order": [ "error", { - "groups": ["builtin", "external", "parent", "sibling", "index"], - "pathGroups": [ + groups: ["builtin", "external", "parent", "sibling", "index"], + pathGroups: [ { pattern: "@custom-lib/**", group: "external", position: "after", }, ], - "pathGroupsExcludedImportTypes": ["builtin"], - "alphabetize": { + pathGroupsExcludedImportTypes: ["builtin"], + alphabetize: { order: "asc", }, - "newlines-between": "always", }, ], "sort-imports": ["off"], diff --git a/packages/server/src/lib/files/FileManager.ts b/packages/server/src/lib/files/FileManager.ts index ed5ee64b..061f9827 100644 --- a/packages/server/src/lib/files/FileManager.ts +++ b/packages/server/src/lib/files/FileManager.ts @@ -3,7 +3,6 @@ import { MIMEType } from "util"; import type { File } from "@prisma/client"; import { Service } from "typedi"; -import { FileRepository } from "#repositories/file/fileRepository.js"; import { serveOrigin } from "../../environment.js"; import { logger } from "../logging/standardLogging.js"; @@ -13,6 +12,7 @@ import type { StorageProvider, } from "./storage/StorageProvider.js"; import { UnsupportedAccessMethod } from "./storage/StorageProvider.js"; +import { FileRepository } from "#repositories/file/fileRepository.js"; const FILE_API = new URL("/api/file/download/", serveOrigin); diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index 6c2ecc45..783c3ddd 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -5,6 +5,9 @@ import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; +import { ConcreteError, toBasicError } from "./error/error.js"; +import { CatchableConcreteError } from "./formatError.js"; +import { logger } from "./logging/logger.js"; import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; import { DeviceResolver } from "#resolvers/DeviceResolver.js"; import { EventResolver } from "#resolvers/EventResolver.js"; @@ -26,9 +29,6 @@ import { PointEntryResolver } from "#resolvers/PointEntryResolver.js"; import { PointOpportunityResolver } from "#resolvers/PointOpportunityResolver.js"; import { TeamResolver } from "#resolvers/TeamResolver.js"; -import { ConcreteError, toBasicError } from "./error/error.js"; -import { CatchableConcreteError } from "./formatError.js"; -import { logger } from "./logging/logger.js"; const schemaPath = fileURLToPath( new URL("../../../../schema.graphql", import.meta.url) diff --git a/packages/server/src/lib/notification/ExpoNotificationProvider.ts b/packages/server/src/lib/notification/ExpoNotificationProvider.ts index 55adc631..0deb0a94 100644 --- a/packages/server/src/lib/notification/ExpoNotificationProvider.ts +++ b/packages/server/src/lib/notification/ExpoNotificationProvider.ts @@ -9,17 +9,17 @@ import { Expo } from "expo-server-sdk"; import { DateTime } from "luxon"; import { Service } from "typedi"; -import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; -import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; -import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; import { isDevelopment } from "../../environment.js"; import { logger } from "../logging/standardLogging.js"; - import type { NotificationAudience, NotificationProvider, SendableNotification, } from "./NotificationProvider.js"; +import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; +import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; +import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; + function makeExpoNotifications( content: { diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index 6dda0e0e..6c95e474 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -7,10 +7,6 @@ import { import { Err, None, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { CompositeError } from "#error/composite.js"; -import { InvariantError, NotFoundError } from "#error/direct.js"; -import { toBasicError } from "#error/error.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { MarathonRepository } from "../marathon/MarathonRepository.js"; import { MembershipRepository } from "../membership/MembershipRepository.js"; @@ -25,6 +21,10 @@ import { buildCommitteeOrder, buildCommitteeWhere, } from "./committeeRepositoryUtils.js"; +import { CompositeError } from "#error/composite.js"; +import { InvariantError, NotFoundError } from "#error/direct.js"; +import { toBasicError } from "#error/error.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; // Make sure that we are exporting a description for every committee CommitteeDescriptions[ diff --git a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts index c30ca9cf..d515ded7 100644 --- a/packages/server/src/repositories/committee/committeeRepositoryUtils.ts +++ b/packages/server/src/repositories/committee/committeeRepositoryUtils.ts @@ -1,12 +1,12 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { CommitteeFilters } from "./CommitteeRepository.js"; import { dateFilterToPrisma, oneOfFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { CommitteeFilters } from "./CommitteeRepository.js"; export function buildCommitteeOrder( order: readonly [key: string, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/repositories/configuration/ConfigurationRepository.ts b/packages/server/src/repositories/configuration/ConfigurationRepository.ts index 825c5c3a..dc07812b 100644 --- a/packages/server/src/repositories/configuration/ConfigurationRepository.ts +++ b/packages/server/src/repositories/configuration/ConfigurationRepository.ts @@ -3,13 +3,13 @@ import type { SortDirection } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { SimpleUniqueParam } from "../shared.js"; import { buildConfigurationOrder, buildConfigurationWhere, } from "./configurationRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; const configurationStringKeys = ["key", "value"] as const; type ConfigurationStringKey = (typeof configurationStringKeys)[number]; diff --git a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts index 173ff79c..63719480 100644 --- a/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts +++ b/packages/server/src/repositories/configuration/configurationRepositoryUtils.ts @@ -1,12 +1,12 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { ConfigurationFilters } from "./ConfigurationRepository.js"; import { dateFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { ConfigurationFilters } from "./ConfigurationRepository.js"; export function buildConfigurationOrder( order: readonly [key: string, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index cd492e24..b4e58875 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -4,14 +4,14 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Result } from "ts-results-es"; import { Service } from "typedi"; +import { PersonRepository } from "../person/PersonRepository.js"; +import { RepositoryError } from "../shared.js"; +import { buildDeviceOrder, buildDeviceWhere } from "./deviceRepositoryUtils.js"; import { NotFoundError } from "#error/direct.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { NotificationAudience } from "#notification/NotificationProvider.js"; -import { PersonRepository } from "../person/PersonRepository.js"; -import { RepositoryError } from "../shared.js"; -import { buildDeviceOrder, buildDeviceWhere } from "./deviceRepositoryUtils.js"; const deviceStringKeys = ["expoPushToken"] as const; type DeviceStringKey = (typeof deviceStringKeys)[number]; diff --git a/packages/server/src/repositories/device/deviceRepositoryUtils.ts b/packages/server/src/repositories/device/deviceRepositoryUtils.ts index b98b2d58..1f49d8a8 100644 --- a/packages/server/src/repositories/device/deviceRepositoryUtils.ts +++ b/packages/server/src/repositories/device/deviceRepositoryUtils.ts @@ -1,12 +1,12 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { DeviceFilters } from "./DeviceRepository.js"; import { dateFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { DeviceFilters } from "./DeviceRepository.js"; export function buildDeviceOrder( order: readonly [key: string, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/repositories/event/EventRepository.ts b/packages/server/src/repositories/event/EventRepository.ts index ef0e40ef..86cee35b 100644 --- a/packages/server/src/repositories/event/EventRepository.ts +++ b/packages/server/src/repositories/event/EventRepository.ts @@ -2,9 +2,9 @@ import { Prisma, PrismaClient } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; +import { buildEventOrder, buildEventWhere } from "./eventRepositoryUtils.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import { buildEventOrder, buildEventWhere } from "./eventRepositoryUtils.js"; const eventBooleanKeys = [] as const; type EventBooleanKey = (typeof eventBooleanKeys)[number]; diff --git a/packages/server/src/repositories/event/eventRepositoryUtils.ts b/packages/server/src/repositories/event/eventRepositoryUtils.ts index 2b8721fa..1e1f071a 100644 --- a/packages/server/src/repositories/event/eventRepositoryUtils.ts +++ b/packages/server/src/repositories/event/eventRepositoryUtils.ts @@ -2,12 +2,12 @@ import type { Prisma } from "@prisma/client"; import type { FilterItem } from "@ukdanceblue/common"; import { SortDirection } from "@ukdanceblue/common"; +import type { EventFilters, EventOrderKeys } from "./EventRepository.ts"; import { dateFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { EventFilters, EventOrderKeys } from "./EventRepository.ts"; export function buildEventOrder( order: diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 01827959..04f91ed4 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -3,14 +3,14 @@ import { DateTime } from "luxon"; import { Err, None, Ok, Option, Result } from "ts-results-es"; import { Service } from "typedi"; +import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; +import { MarathonRepository } from "../marathon/MarathonRepository.js"; +import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; import { CompositeError } from "#error/composite.js"; import { NotFoundError } from "#error/direct.js"; import { BasicError } from "#error/error.js"; import { PrismaError, SomePrismaError } from "#error/prisma.js"; import { logger } from "#logging/standardLogging.js"; -import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import { MarathonRepository } from "../marathon/MarathonRepository.js"; -import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; export type UniqueDbFundsTeamParam = | { diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index e5b6728d..c15fa2c7 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -10,18 +10,18 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, None, Ok, Option, Result, Some } from "ts-results-es"; import { Service } from "typedi"; -import { ActionDeniedError } from "#error/control.js"; -import { NotFoundError } from "#error/direct.js"; -import { BasicError } from "#error/error.js"; -import { SomePrismaError } from "#error/prisma.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { UniquePersonParam } from "../person/PersonRepository.js"; import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; - import { buildFundraisingEntryOrder, buildFundraisingEntryWhere, } from "./fundraisingEntryRepositoryUtils.js"; +import { ActionDeniedError } from "#error/control.js"; +import { NotFoundError } from "#error/direct.js"; +import { BasicError } from "#error/error.js"; +import { SomePrismaError } from "#error/prisma.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const fundraisingEntryBooleanKeys = [] as const; type FundraisingEntryBooleanKey = (typeof fundraisingEntryBooleanKeys)[number]; diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index f2c5ef77..9314c520 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -3,6 +3,10 @@ import { SortDirection } from "@ukdanceblue/common"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; +import type { + FundraisingEntryFilters, + FundraisingEntryOrderKeys, +} from "./FundraisingRepository.js"; import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, @@ -11,10 +15,6 @@ import { stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - FundraisingEntryFilters, - FundraisingEntryOrderKeys, -} from "./FundraisingRepository.js"; export function buildFundraisingEntryOrder( order: diff --git a/packages/server/src/repositories/image/ImageRepository.ts b/packages/server/src/repositories/image/ImageRepository.ts index b059b4a9..2e632bf5 100644 --- a/packages/server/src/repositories/image/ImageRepository.ts +++ b/packages/server/src/repositories/image/ImageRepository.ts @@ -2,9 +2,9 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; +import { buildImageOrder, buildImageWhere } from "./imageRepositoryUtils.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import { buildImageOrder, buildImageWhere } from "./imageRepositoryUtils.js"; const imageBooleanKeys = [] as const; type ImageBooleanKey = (typeof imageBooleanKeys)[number]; diff --git a/packages/server/src/repositories/image/imageRepositoryUtils.ts b/packages/server/src/repositories/image/imageRepositoryUtils.ts index 39193821..7cd05775 100644 --- a/packages/server/src/repositories/image/imageRepositoryUtils.ts +++ b/packages/server/src/repositories/image/imageRepositoryUtils.ts @@ -1,13 +1,13 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { ImageFilters } from "./ImageRepository.ts"; import { dateFilterToPrisma, numericFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { ImageFilters } from "./ImageRepository.ts"; export function buildImageOrder( order: readonly [key: string, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index fabbdc3e..53f8de97 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -3,14 +3,14 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "#error/direct.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, type RepositoryError } from "../shared.js"; - import { buildMarathonOrder, buildMarathonWhere, } from "./marathonRepositoryUtils.js"; +import { NotFoundError } from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const marathonBooleanKeys = [] as const; type MarathonBooleanKey = (typeof marathonBooleanKeys)[number]; diff --git a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts index b155acf4..c9e03920 100644 --- a/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts +++ b/packages/server/src/repositories/marathon/marathonRepositoryUtils.ts @@ -1,15 +1,15 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { + MarathonFilters, + MarathonOrderKeys, +} from "./MarathonRepository.ts"; import { dateFilterToPrisma, oneOfFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - MarathonFilters, - MarathonOrderKeys, -} from "./MarathonRepository.ts"; export function buildMarathonOrder( order: diff --git a/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts b/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts index 4741395f..d3592bda 100644 --- a/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts +++ b/packages/server/src/repositories/marathonHour/MarathonHourRepository.ts @@ -2,12 +2,12 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - import { buildMarathonHourOrder, buildMarathonHourWhere, } from "./marathonHourRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const marathonHourBooleanKeys = [] as const; type MarathonHourBooleanKey = (typeof marathonHourBooleanKeys)[number]; diff --git a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts index 55f15faf..26072c9d 100644 --- a/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts +++ b/packages/server/src/repositories/marathonHour/marathonHourRepositoryUtils.ts @@ -1,16 +1,16 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { + MarathonHourFilters, + MarathonHourOrderKeys, +} from "./MarathonHourRepository.ts"; import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - MarathonHourFilters, - MarathonHourOrderKeys, -} from "./MarathonHourRepository.ts"; export function buildMarathonHourOrder( order: diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index be3abaed..1c8aa982 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -3,13 +3,13 @@ import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "#error/direct.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, type RepositoryError, type SimpleUniqueParam, } from "../shared.js"; +import { NotFoundError } from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; const membershipBooleanKeys = [] as const; type MembershipBooleanKey = (typeof membershipBooleanKeys)[number]; diff --git a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts index a73a365b..a95afc94 100644 --- a/packages/server/src/repositories/membership/membershipRepositoryUtils.ts +++ b/packages/server/src/repositories/membership/membershipRepositoryUtils.ts @@ -1,9 +1,9 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { MembershipFilters } from "./MembershipRepository.ts"; import { dateFilterToPrisma } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { MembershipFilters } from "./MembershipRepository.ts"; export function buildMembershipOrder( order: readonly [key: string, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/repositories/notification/NotificationRepository.ts b/packages/server/src/repositories/notification/NotificationRepository.ts index b65a5c78..2bb21eac 100644 --- a/packages/server/src/repositories/notification/NotificationRepository.ts +++ b/packages/server/src/repositories/notification/NotificationRepository.ts @@ -3,12 +3,11 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - import { buildNotificationOrder, buildNotificationWhere, } from "./notificationRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; const notificationBooleanKeys = [] as const; type NotificationBooleanKey = (typeof notificationBooleanKeys)[number]; diff --git a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts index 4f894fe3..6f3c4973 100644 --- a/packages/server/src/repositories/notification/notificationRepositoryUtils.ts +++ b/packages/server/src/repositories/notification/notificationRepositoryUtils.ts @@ -1,16 +1,16 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { + NotificationFilters, + NotificationOrderKeys, +} from "./NotificationRepository.ts"; import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - NotificationFilters, - NotificationOrderKeys, -} from "./NotificationRepository.ts"; export function buildNotificationOrder( order: diff --git a/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts b/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts index 447b0301..6189cbe7 100644 --- a/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts +++ b/packages/server/src/repositories/notificationDelivery/NotificationDeliveryRepository.ts @@ -4,12 +4,12 @@ import type { ExpoPushReceipt, ExpoPushTicket } from "expo-server-sdk"; import type { DateTime } from "luxon"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - import { buildNotificationDeliveryOrder, buildNotificationDeliveryWhere, } from "./notificationDeliveryRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const notificationDeliveryBooleanKeys = [] as const; type NotificationDeliveryBooleanKey = diff --git a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts index e00c36b1..454882b5 100644 --- a/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts +++ b/packages/server/src/repositories/notificationDelivery/notificationDeliveryRepositoryUtils.ts @@ -1,15 +1,15 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { + NotificationDeliveryFilters, + NotificationDeliveryOrderKeys, +} from "./NotificationDeliveryRepository.js"; import { dateFilterToPrisma, oneOfFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - NotificationDeliveryFilters, - NotificationDeliveryOrderKeys, -} from "./NotificationDeliveryRepository.js"; export function buildNotificationDeliveryOrder( order: diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 88de6297..dad066f4 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -16,13 +16,6 @@ import { import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { ActionDeniedError } from "#error/control.js"; -import { - InvalidArgumentError, - InvariantError, - NotFoundError, -} from "#error/direct.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import { handleRepositoryError, @@ -33,6 +26,13 @@ import { import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; import { findPersonForLogin } from "#auth/findPersonForLogin.js"; +import { ActionDeniedError } from "#error/control.js"; +import { + InvalidArgumentError, + InvariantError, + NotFoundError, +} from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; const personStringKeys = ["name", "email", "linkblue"] as const; type PersonStringKey = (typeof personStringKeys)[number]; diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index b8318243..60c9bbc8 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -3,13 +3,13 @@ import { SortDirection } from "@ukdanceblue/common"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; +import type { PersonFilters, PersonOrderKeys } from "./PersonRepository.js"; import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { PersonFilters, PersonOrderKeys } from "./PersonRepository.js"; export function buildPersonOrder( order: diff --git a/packages/server/src/repositories/pointEntry/PointEntryRepository.ts b/packages/server/src/repositories/pointEntry/PointEntryRepository.ts index 7f9205f3..ea924bcb 100644 --- a/packages/server/src/repositories/pointEntry/PointEntryRepository.ts +++ b/packages/server/src/repositories/pointEntry/PointEntryRepository.ts @@ -2,12 +2,12 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - import { buildPointEntryOrder, buildPointEntryWhere, } from "./pointEntryRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const pointEntryBooleanKeys = [] as const; type PointEntryBooleanKey = (typeof pointEntryBooleanKeys)[number]; diff --git a/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts b/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts index 2893d7fa..46334358 100644 --- a/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts +++ b/packages/server/src/repositories/pointOpportunity/PointOpportunityRepository.ts @@ -3,12 +3,12 @@ import { Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - import { buildPointOpportunityOrder, buildPointOpportunityWhere, } from "./pointOpportunityRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; + const pointOpportunityBooleanKeys = [] as const; type PointOpportunityBooleanKey = (typeof pointOpportunityBooleanKeys)[number]; diff --git a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts index 8ee59d55..2d2ee8da 100644 --- a/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts +++ b/packages/server/src/repositories/pointOpportunity/pointOpportunityRepositoryUtils.ts @@ -1,16 +1,16 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { + PointOpportunityFilters, + PointOpportunityOrderKeys, +} from "./PointOpportunityRepository.ts"; import { dateFilterToPrisma, oneOfFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { - PointOpportunityFilters, - PointOpportunityOrderKeys, -} from "./PointOpportunityRepository.ts"; export function buildPointOpportunityOrder( order: diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index cc23de71..be598adf 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -7,11 +7,11 @@ import type { import { TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; import type { SimpleUniqueParam } from "../shared.js"; import { buildTeamOrder, buildTeamWhere } from "./teamRepositoryUtils.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; const teamBooleanKeys = [] as const; type TeamBooleanKey = (typeof teamBooleanKeys)[number]; diff --git a/packages/server/src/repositories/team/teamRepositoryUtils.ts b/packages/server/src/repositories/team/teamRepositoryUtils.ts index c045ad50..e89d16bc 100644 --- a/packages/server/src/repositories/team/teamRepositoryUtils.ts +++ b/packages/server/src/repositories/team/teamRepositoryUtils.ts @@ -1,6 +1,7 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import type { TeamFilters, TeamOrderKeys } from "./TeamRepository.ts"; import { dateFilterToPrisma, numericFilterToPrisma, @@ -8,7 +9,6 @@ import { stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; -import type { TeamFilters, TeamOrderKeys } from "./TeamRepository.ts"; export function buildTeamOrder( order: readonly [key: TeamOrderKeys, sort: SortDirection][] | null | undefined diff --git a/packages/server/src/resolvers/AdministrationResolver.ts b/packages/server/src/resolvers/AdministrationResolver.ts index 6996efbd..7c3cbcb3 100644 --- a/packages/server/src/resolvers/AdministrationResolver.ts +++ b/packages/server/src/resolvers/AdministrationResolver.ts @@ -4,8 +4,8 @@ import { join } from "path"; import { AccessControl, AccessLevel } from "@ukdanceblue/common"; import { FieldResolver, ObjectType, Query, Resolver } from "type-graphql"; -import { auditLoggerFileName } from "#logging/auditLogging.js"; import { logDir } from "../environment.js"; +import { auditLoggerFileName } from "#logging/auditLogging.js"; @ObjectType() export class Administration { diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index a3e9a303..52334a11 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -21,15 +21,15 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { auditLogger } from "#logging/auditLogging.js"; -import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; -import { configurationModelToResource } from "#repositories/configuration/configurationModelToResource.js"; - import { AbstractGraphQLArrayOkResponse, AbstractGraphQLCreatedResponse, AbstractGraphQLOkResponse, } from "./ApiResponse.js"; +import { auditLogger } from "#logging/auditLogging.js"; +import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; +import { configurationModelToResource } from "#repositories/configuration/configurationModelToResource.js"; + @ObjectType("GetConfigurationByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 0948ced1..dc9da463 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -25,6 +25,10 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { auditLogger } from "#logging/auditLogging.js"; import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; @@ -33,10 +37,6 @@ import { notificationDeliveryModelToResource } from "#repositories/notificationD import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; -import { - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; @ObjectType("GetDeviceByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index eef20692..2a914f92 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -27,6 +27,11 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "./ApiResponse.js"; import { FileManager } from "#files/FileManager.js"; import { auditLogger } from "#logging/auditLogging.js"; import { EventRepository } from "#repositories/event/EventRepository.js"; @@ -37,11 +42,6 @@ import { import { EventImagesRepository } from "#repositories/event/images/EventImagesRepository.js"; import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; @ObjectType("GetEventByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index e2fa28b6..8cf2f30a 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -22,6 +22,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { globalFundraisingAccessParam } from "./FundraisingEntryResolver.js"; import { ConcreteResult } from "#error/result.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; @@ -29,7 +30,6 @@ import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisi import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; -import { globalFundraisingAccessParam } from "./FundraisingEntryResolver.js"; @InputType() class AssignEntryToPersonInput { diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 3715a8ab..7a84743d 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -24,6 +24,7 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; @@ -31,7 +32,6 @@ import { FundraisingEntryRepository } from "#repositories/fundraising/Fundraisin import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ArgsType() export class ListFundraisingEntriesArgs extends FilteredListQueryArgs< diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index 20b89e92..2e480e4d 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -26,6 +26,10 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "./ApiResponse.js"; import { FileManager } from "#files/FileManager.js"; import { generateThumbHash } from "#lib/thumbHash.js"; import { auditLogger } from "#logging/auditLogging.js"; @@ -33,10 +37,6 @@ import { logger } from "#logging/standardLogging.js"; import { ImageRepository } from "#repositories/image/ImageRepository.js"; import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; -import { - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; @ObjectType("GetImageByUuidResponse", { implements: AbstractGraphQLOkResponse }) class GetImageByUuidResponse extends AbstractGraphQLOkResponse { diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index 58e357bd..de833c39 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -23,10 +23,10 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { MarathonHourRepository } from "#repositories/marathonHour/MarathonHourRepository.js"; import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ObjectType("ListMarathonHoursResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 4a5109c8..17349350 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -24,6 +24,7 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; @@ -31,7 +32,6 @@ import { marathonModelToResource } from "#repositories/marathon/marathonModelToR import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; @ObjectType("ListMarathonsResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 0df93a3c..4e0ea0e7 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -20,7 +20,6 @@ import { Ok } from "ts-results-es"; import { Arg, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { ConfigurationResolver } from "./ConfigurationResolver.js"; import { DeviceResolver } from "./DeviceResolver.js"; @@ -36,6 +35,7 @@ import { PersonResolver } from "./PersonResolver.js"; import { PointEntryResolver } from "./PointEntryResolver.js"; import { PointOpportunityResolver } from "./PointOpportunityResolver.js"; import { TeamResolver } from "./TeamResolver.js"; +import { ConcreteResult } from "#error/result.js"; @Resolver(() => Node) @Service() diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 0445839e..9c97844f 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -28,6 +28,11 @@ import { } from "type-graphql"; import { Inject, Service } from "typedi"; +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "./ApiResponse.js"; import { NotificationScheduler } from "#jobs/NotificationScheduler.js"; import { ExpoNotificationProvider } from "#notification/ExpoNotificationProvider.js"; import * as NotificationProviderJs from "#notification/NotificationProvider.js"; @@ -36,11 +41,6 @@ import { notificationModelToResource } from "#repositories/notification/notifica import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; import { notificationDeliveryModelToResource } from "#repositories/notificationDelivery/notificationDeliveryModelToResource.js"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; @ObjectType("GetNotificationByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index e7f18ed6..6e694222 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -32,6 +32,13 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; +import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; +import { + ListFundraisingEntriesArgs, + ListFundraisingEntriesResponse, + globalFundraisingAccessParam, +} from "./FundraisingEntryResolver.js"; +import type { GraphQLContext } from "./context.js"; import { ConcreteError } from "#error/error.js"; import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; @@ -48,13 +55,6 @@ import { import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; -import { - ListFundraisingEntriesArgs, - ListFundraisingEntriesResponse, - globalFundraisingAccessParam, -} from "./FundraisingEntryResolver.js"; -import type { GraphQLContext } from "./context.js"; @ObjectType("ListPeopleResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 3c17eaf3..521a5cd6 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -27,6 +27,11 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "./ApiResponse.js"; import { NotFoundError } from "#error/direct.js"; import { ConcreteResult } from "#error/result.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; @@ -36,11 +41,6 @@ import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryMo import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; @ObjectType("GetPointEntryByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index 0da2d1dd..86c43ae5 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -26,15 +26,15 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { eventModelToResource } from "#repositories/event/eventModelToResource.js"; -import { PointOpportunityRepository } from "#repositories/pointOpportunity/PointOpportunityRepository.js"; -import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; - import { AbstractGraphQLCreatedResponse, AbstractGraphQLOkResponse, AbstractGraphQLPaginatedResponse, } from "./ApiResponse.js"; +import { eventModelToResource } from "#repositories/event/eventModelToResource.js"; +import { PointOpportunityRepository } from "#repositories/pointOpportunity/PointOpportunityRepository.js"; +import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; + @ObjectType("SinglePointOpportunityResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index b4edcd0b..8ec9be8a 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -35,16 +35,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { CatchableConcreteError } from "#lib/formatError.js"; -import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; -import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; -import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; -import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; -import { membershipModelToResource } from "#repositories/membership/membershipModelToResource.js"; -import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; -import { TeamRepository } from "#repositories/team/TeamRepository.js"; -import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; - import { AbstractGraphQLCreatedResponse, AbstractGraphQLOkResponse, @@ -56,6 +46,16 @@ import { globalFundraisingAccessParam, } from "./FundraisingEntryResolver.js"; import * as Context from "./context.js"; +import { CatchableConcreteError } from "#lib/formatError.js"; +import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; +import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; +import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; +import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; +import { membershipModelToResource } from "#repositories/membership/membershipModelToResource.js"; +import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; +import { TeamRepository } from "#repositories/team/TeamRepository.js"; +import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; + @ObjectType("SingleTeamResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/routes/api/auth/login.ts b/packages/server/src/routes/api/auth/login.ts index 3258a010..77c24518 100644 --- a/packages/server/src/routes/api/auth/login.ts +++ b/packages/server/src/routes/api/auth/login.ts @@ -2,9 +2,9 @@ import type { Context } from "koa"; import { generators } from "openid-client"; import { Container } from "typedi"; +import { makeOidcClient } from "./oidcClient.js"; import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; -import { makeOidcClient } from "./oidcClient.js"; // TODO: convert to OAuth2 export const login = async (ctx: Context) => { diff --git a/packages/server/src/routes/api/auth/oidcCallback.ts b/packages/server/src/routes/api/auth/oidcCallback.ts index 38b93ef8..152e84ed 100644 --- a/packages/server/src/routes/api/auth/oidcCallback.ts +++ b/packages/server/src/routes/api/auth/oidcCallback.ts @@ -6,12 +6,12 @@ import type { Context } from "koa"; import { DateTime } from "luxon"; import { Container } from "typedi"; +import { makeOidcClient } from "./oidcClient.js"; import { makeUserJwt } from "#auth/index.js"; import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; -import { makeOidcClient } from "./oidcClient.js"; export const oidcCallback = async (ctx: Context) => { const oidcClient = await makeOidcClient(ctx.request); diff --git a/packages/server/src/routes/api/upload/index.ts b/packages/server/src/routes/api/upload/index.ts index 0bae79bf..6c124748 100644 --- a/packages/server/src/routes/api/upload/index.ts +++ b/packages/server/src/routes/api/upload/index.ts @@ -5,11 +5,11 @@ import type { File } from "@prisma/client"; import { koaBody } from "koa-body"; import { Container } from "typedi"; +import { maxFileSize } from "../../../environment.js"; import { FileManager } from "#files/FileManager.js"; import { generateThumbHash } from "#lib/thumbHash.js"; import { logger } from "#logging/standardLogging.js"; import { ImageRepository } from "#repositories/image/ImageRepository.js"; -import { maxFileSize } from "../../../environment.js"; const uploadRouter = new Router({ prefix: "/upload" }).post( "/image/:uuid", diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index 846997fa..1ae64239 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -1,10 +1,10 @@ import { CommitteeIdentifier, CommitteeRole } from "@ukdanceblue/common"; import { Container } from "typedi"; +import { isDevelopment } from "./environment.js"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; -import { isDevelopment } from "./environment.js"; if (!isDevelopment) { throw new Error("Seeding is only allowed in development mode"); diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 68c4b78f..25ad15e2 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -13,17 +13,17 @@ import type { DefaultState } from "koa"; import Koa from "koa"; import { koaBody } from "koa-body"; +import { + applicationHost, + applicationPort, + loggingLevel, +} from "./environment.js"; import { logger } from "#logging/logger.js"; import type { GraphQLContext } from "#resolvers/context.js"; import eventsApiRouter from "#routes/api/events/index.js"; import fileRouter from "#routes/api/file/index.js"; import healthCheckRouter from "#routes/api/healthcheck/index.js"; import uploadRouter from "#routes/api/upload/index.js"; -import { - applicationHost, - applicationPort, - loggingLevel, -} from "./environment.js"; const basicLoggingPlugin: ApolloServerPlugin = { requestDidStart(requestContext) { From f8231854851130c01677d63194dab2b4217877d7 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:45:35 +0000 Subject: [PATCH 142/153] Add more import aliasing --- .vscode/settings.json | 2 +- packages/server/package.json | 3 +- packages/server/src/index.ts | 2 +- .../server/src/lib/auth/findPersonForLogin.ts | 2 +- packages/server/src/lib/auth/index.ts | 2 +- packages/server/src/lib/files/FileManager.ts | 5 ++-- .../lib/files/storage/LocalStorageProvider.ts | 5 ++-- packages/server/src/lib/formatError.ts | 2 +- .../src/lib/fundraising/DbFundsProvider.ts | 18 +++++------- .../lib/fundraising/FundraisingProvider.ts | 2 +- packages/server/src/lib/graphqlSchema.ts | 5 ++-- .../server/src/lib/logging/auditLogging.ts | 2 +- packages/server/src/lib/logging/sqlLogging.ts | 2 +- .../server/src/lib/logging/standardLogging.ts | 2 +- .../notification/ExpoNotificationProvider.ts | 5 ++-- .../committee/CommitteeRepository.ts | 18 ++++++------ .../configuration/ConfigurationRepository.ts | 4 +-- .../device/DeviceRepository.test.ts | 4 +-- .../repositories/device/DeviceRepository.ts | 5 ++-- .../fundraising/DBFundsRepository.ts | 9 ++++-- .../fundraising/FundraisingRepository.ts | 8 +++-- .../marathon/MarathonRepository.ts | 6 ++-- .../membership/MembershipRepository.ts | 6 ++-- .../repositories/person/PersonRepository.ts | 12 ++++---- .../person/personModelToResource.ts | 4 +-- .../src/repositories/team/TeamRepository.ts | 6 ++-- .../src/resolvers/AdministrationResolver.ts | 2 +- .../src/resolvers/ConfigurationResolver.ts | 9 +++--- .../server/src/resolvers/DeviceResolver.ts | 9 +++--- .../server/src/resolvers/EventResolver.ts | 11 ++++--- .../FundraisingAssignmentResolver.ts | 3 +- .../src/resolvers/FundraisingEntryResolver.ts | 3 +- .../server/src/resolvers/ImageResolver.ts | 9 +++--- packages/server/src/resolvers/LoginState.ts | 2 +- .../src/resolvers/MarathonHourResolver.ts | 3 +- .../server/src/resolvers/MarathonResolver.ts | 3 +- packages/server/src/resolvers/NodeResolver.ts | 29 +++++++++---------- .../src/resolvers/NotificationResolver.ts | 11 ++++--- .../server/src/resolvers/PersonResolver.ts | 15 +++++----- .../src/resolvers/PointEntryResolver.ts | 11 ++++--- .../src/resolvers/PointOpportunityResolver.ts | 9 +++--- packages/server/src/resolvers/TeamResolver.ts | 23 +++++++-------- packages/server/src/resolvers/index.ts | 4 +-- .../server/src/routes/api/auth/oidcClient.ts | 2 +- .../server/src/routes/api/upload/index.ts | 2 +- packages/server/src/seed.ts | 2 +- packages/server/src/server.ts | 6 +--- packages/server/tsconfig.json | 3 +- 48 files changed, 147 insertions(+), 165 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e4f67123..b21907db 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "editor.formatOnSave": true, "editor.tabSize": 2, "editor.codeActionsOnSave": { - "source.organizeImports": "explicit", + "source.organizeImports": "never", "source.fixAll": "explicit" }, "search.exclude": { diff --git a/packages/server/package.json b/packages/server/package.json index e2b82459..692ecf36 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -94,7 +94,8 @@ "#jobs/*.js": "./dist/jobs/*.js", "#repositories/*.js": "./dist/repositories/*.js", "#resolvers/*.js": "./dist/resolvers/*.js", - "#routes/*.js": "./dist/routes/*.js" + "#routes/*.js": "./dist/routes/*.js", + "#environment": "./dist/environment.js" }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781" } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index eb579736..a02e96d1 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -7,7 +7,7 @@ import "reflect-metadata"; logger.info("DanceBlue Server Starting"); -await import("./environment.js"); +await import("#environment"); logger.info("Loaded environment variables"); await import("./prisma.js"); diff --git a/packages/server/src/lib/auth/findPersonForLogin.ts b/packages/server/src/lib/auth/findPersonForLogin.ts index e203a0c8..7d95ab40 100644 --- a/packages/server/src/lib/auth/findPersonForLogin.ts +++ b/packages/server/src/lib/auth/findPersonForLogin.ts @@ -2,7 +2,7 @@ import type { AuthSource, Prisma, PrismaClient } from "@prisma/client"; import type { DbRole } from "@ukdanceblue/common"; import { MembershipPositionType } from "@ukdanceblue/common"; -import { logger } from "../logging/logger.js"; +import { logger } from "#logging/logger.js"; // TODO: rework this whole thing, it's pretty boated and confusing diff --git a/packages/server/src/lib/auth/index.ts b/packages/server/src/lib/auth/index.ts index 31b28188..170ad928 100644 --- a/packages/server/src/lib/auth/index.ts +++ b/packages/server/src/lib/auth/index.ts @@ -3,7 +3,7 @@ import { AuthSource } from "@ukdanceblue/common"; import jsonwebtoken from "jsonwebtoken"; import type { Request } from "koa"; -import { jwtSecret } from "../../environment.js"; +import { jwtSecret } from "#environment"; const jwtIssuer = "https://app.danceblue.org"; diff --git a/packages/server/src/lib/files/FileManager.ts b/packages/server/src/lib/files/FileManager.ts index 061f9827..18ff9c99 100644 --- a/packages/server/src/lib/files/FileManager.ts +++ b/packages/server/src/lib/files/FileManager.ts @@ -3,15 +3,14 @@ import { MIMEType } from "util"; import type { File } from "@prisma/client"; import { Service } from "typedi"; -import { serveOrigin } from "../../environment.js"; -import { logger } from "../logging/standardLogging.js"; - import { LocalStorageProvider } from "./storage/LocalStorageProvider.js"; import type { StorableFile, StorageProvider, } from "./storage/StorageProvider.js"; import { UnsupportedAccessMethod } from "./storage/StorageProvider.js"; +import { serveOrigin } from "#environment"; +import { logger } from "#logging/standardLogging.js"; import { FileRepository } from "#repositories/file/fileRepository.js"; const FILE_API = new URL("/api/file/download/", serveOrigin); diff --git a/packages/server/src/lib/files/storage/LocalStorageProvider.ts b/packages/server/src/lib/files/storage/LocalStorageProvider.ts index 45359b00..655202a8 100644 --- a/packages/server/src/lib/files/storage/LocalStorageProvider.ts +++ b/packages/server/src/lib/files/storage/LocalStorageProvider.ts @@ -7,15 +7,14 @@ import type { MIMEType } from "util"; import { DateTime } from "luxon"; import { Service } from "typedi"; -import { servePath, uploadPath } from "../../../environment.js"; -import { logger } from "../../logging/standardLogging.js"; - import type { StorableFile, StorageProvider, UnsupportedAccessMethod, } from "./StorageProvider.js"; import { BaseStorageProvider } from "./StorageProvider.js"; +import { servePath, uploadPath } from "#environment"; +import { logger } from "#logging/standardLogging.js"; /** * Determines if the location a path refers to is within `servePath` diff --git a/packages/server/src/lib/formatError.ts b/packages/server/src/lib/formatError.ts index 3d3219b1..f1b4f76f 100644 --- a/packages/server/src/lib/formatError.ts +++ b/packages/server/src/lib/formatError.ts @@ -14,7 +14,7 @@ import { GraphQLError } from "graphql"; import jwt from "jsonwebtoken"; import type { Writable } from "utility-types"; -import type { ConcreteError } from "./error/error.js"; +import type { ConcreteError } from "#error/error.js"; export interface DbGraphQLFormattedErrorExtensions extends Omit { diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index c44873ab..584ca514 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -4,22 +4,18 @@ import { Err, Ok } from "ts-results-es"; import { Inject, Service } from "typedi"; import { z } from "zod"; -import { - dbFundsApiKeyToken, - dbFundsApiOriginToken, -} from "../../environment.js"; -import { TimeoutError } from "../error/direct.js"; -import { BasicError, toBasicError } from "../error/error.js"; -import { HttpError } from "../error/http.js"; -import { optionOf } from "../error/option.js"; -import { ConcreteResult } from "../error/result.js"; -import { ZodError } from "../error/zod.js"; - import type { FundraisingEntry, FundraisingProvider, FundraisingTeam, } from "./FundraisingProvider.js"; +import { dbFundsApiKeyToken, dbFundsApiOriginToken } from "#environment"; +import { TimeoutError } from "#error/direct.js"; +import { BasicError, toBasicError } from "#error/error.js"; +import { HttpError } from "#error/http.js"; +import { optionOf } from "#error/option.js"; +import { ConcreteResult } from "#error/result.js"; +import { ZodError } from "#error/zod.js"; const dbFundsFundraisingTeamSchema = z.object({ DbNum: z.number().int().nonnegative().describe("The team's dbNum"), diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index c45e81fa..80de16e9 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -2,7 +2,7 @@ import type { MarathonYearString } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; import type { Option } from "ts-results-es"; -import type { ConcreteResult } from "../error/result.js"; +import type { ConcreteResult } from "#error/result.js"; export interface FundraisingTeam { name: string; diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index 783c3ddd..6256ec08 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -5,9 +5,9 @@ import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; -import { ConcreteError, toBasicError } from "./error/error.js"; import { CatchableConcreteError } from "./formatError.js"; -import { logger } from "./logging/logger.js"; +import { ConcreteError, toBasicError } from "#error/error.js"; +import { logger } from "#logging/logger.js"; import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; import { DeviceResolver } from "#resolvers/DeviceResolver.js"; import { EventResolver } from "#resolvers/EventResolver.js"; @@ -29,7 +29,6 @@ import { PointEntryResolver } from "#resolvers/PointEntryResolver.js"; import { PointOpportunityResolver } from "#resolvers/PointOpportunityResolver.js"; import { TeamResolver } from "#resolvers/TeamResolver.js"; - const schemaPath = fileURLToPath( new URL("../../../../schema.graphql", import.meta.url) ); diff --git a/packages/server/src/lib/logging/auditLogging.ts b/packages/server/src/lib/logging/auditLogging.ts index 2a24932e..f32b78d5 100644 --- a/packages/server/src/lib/logging/auditLogging.ts +++ b/packages/server/src/lib/logging/auditLogging.ts @@ -1,7 +1,7 @@ import type { LeveledLogMethod, Logger } from "winston"; import { createLogger, format, transports } from "winston"; -import { isDevelopment, logDir } from "../../environment.js"; +import { isDevelopment, logDir } from "#environment"; export interface AuditLogger extends Logger { /** diff --git a/packages/server/src/lib/logging/sqlLogging.ts b/packages/server/src/lib/logging/sqlLogging.ts index ece96446..58937e5c 100644 --- a/packages/server/src/lib/logging/sqlLogging.ts +++ b/packages/server/src/lib/logging/sqlLogging.ts @@ -1,7 +1,7 @@ import type winston from "winston"; import { createLogger, format, transports } from "winston"; -import { isDevelopment, logDir } from "../../environment.js"; +import { isDevelopment, logDir } from "#environment"; const databaseLogTransport = new transports.File({ filename: "database.log", diff --git a/packages/server/src/lib/logging/standardLogging.ts b/packages/server/src/lib/logging/standardLogging.ts index 81cc6983..0ee37d85 100644 --- a/packages/server/src/lib/logging/standardLogging.ts +++ b/packages/server/src/lib/logging/standardLogging.ts @@ -1,7 +1,7 @@ import type winston from "winston"; import { createLogger, format, transports } from "winston"; -import { logDir, loggingLevel } from "../../environment.js"; +import { logDir, loggingLevel } from "#environment"; export const SyslogLevels = { emerg: 0, diff --git a/packages/server/src/lib/notification/ExpoNotificationProvider.ts b/packages/server/src/lib/notification/ExpoNotificationProvider.ts index 0deb0a94..5628a134 100644 --- a/packages/server/src/lib/notification/ExpoNotificationProvider.ts +++ b/packages/server/src/lib/notification/ExpoNotificationProvider.ts @@ -9,18 +9,17 @@ import { Expo } from "expo-server-sdk"; import { DateTime } from "luxon"; import { Service } from "typedi"; -import { isDevelopment } from "../../environment.js"; -import { logger } from "../logging/standardLogging.js"; import type { NotificationAudience, NotificationProvider, SendableNotification, } from "./NotificationProvider.js"; +import { isDevelopment } from "#environment"; +import { logger } from "#logging/standardLogging.js"; import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; import { NotificationRepository } from "#repositories/notification/NotificationRepository.js"; import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; - function makeExpoNotifications( content: { title: string; diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index 6c95e474..d0ecf7b1 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -7,15 +7,6 @@ import { import { Err, None, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import { MarathonRepository } from "../marathon/MarathonRepository.js"; -import { MembershipRepository } from "../membership/MembershipRepository.js"; -import { - RepositoryError, - SimpleUniqueParam, - handleRepositoryError, -} from "../shared.js"; - import * as CommitteeDescriptions from "./committeeDescriptions.js"; import { buildCommitteeOrder, @@ -25,6 +16,15 @@ import { CompositeError } from "#error/composite.js"; import { InvariantError, NotFoundError } from "#error/direct.js"; import { toBasicError } from "#error/error.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; +import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; +import { MembershipRepository } from "#repositories/membership/MembershipRepository.js"; +import { + RepositoryError, + SimpleUniqueParam, + handleRepositoryError, +} from "#repositories/shared.js"; + // Make sure that we are exporting a description for every committee CommitteeDescriptions[ diff --git a/packages/server/src/repositories/configuration/ConfigurationRepository.ts b/packages/server/src/repositories/configuration/ConfigurationRepository.ts index dc07812b..c226220e 100644 --- a/packages/server/src/repositories/configuration/ConfigurationRepository.ts +++ b/packages/server/src/repositories/configuration/ConfigurationRepository.ts @@ -3,13 +3,13 @@ import type { SortDirection } from "@ukdanceblue/common"; import type { DateTime } from "luxon"; import { Service } from "typedi"; -import { SimpleUniqueParam } from "../shared.js"; - import { buildConfigurationOrder, buildConfigurationWhere, } from "./configurationRepositoryUtils.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import { SimpleUniqueParam } from "#repositories/shared.js"; + const configurationStringKeys = ["key", "value"] as const; type ConfigurationStringKey = (typeof configurationStringKeys)[number]; diff --git a/packages/server/src/repositories/device/DeviceRepository.test.ts b/packages/server/src/repositories/device/DeviceRepository.test.ts index 00e4a512..8597979c 100644 --- a/packages/server/src/repositories/device/DeviceRepository.test.ts +++ b/packages/server/src/repositories/device/DeviceRepository.test.ts @@ -1,8 +1,8 @@ import { beforeEach, describe, expect, it } from "vitest"; -import { makePrismaMock } from "../../testing/PrismaMock.js"; - import { DeviceRepository } from "./DeviceRepository.js"; +import { makePrismaMock } from "#repositories/../testing/PrismaMock.js"; + describe("deviceRepository", () => { const { prismaMock, resetMocks } = makePrismaMock(); diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index b4e58875..0d4ea7df 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -4,14 +4,13 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Result } from "ts-results-es"; import { Service } from "typedi"; -import { PersonRepository } from "../person/PersonRepository.js"; -import { RepositoryError } from "../shared.js"; import { buildDeviceOrder, buildDeviceWhere } from "./deviceRepositoryUtils.js"; import { NotFoundError } from "#error/direct.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { NotificationAudience } from "#notification/NotificationProvider.js"; - +import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { RepositoryError } from "#repositories/shared.js"; const deviceStringKeys = ["expoPushToken"] as const; type DeviceStringKey = (typeof deviceStringKeys)[number]; diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index 04f91ed4..beb780b1 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -3,14 +3,17 @@ import { DateTime } from "luxon"; import { Err, None, Ok, Option, Result } from "ts-results-es"; import { Service } from "typedi"; -import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import { MarathonRepository } from "../marathon/MarathonRepository.js"; -import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; import { CompositeError } from "#error/composite.js"; import { NotFoundError } from "#error/direct.js"; import { BasicError } from "#error/error.js"; import { PrismaError, SomePrismaError } from "#error/prisma.js"; import { logger } from "#logging/standardLogging.js"; +import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; +import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; +import { + SimpleUniqueParam, + handleRepositoryError, +} from "#repositories/shared.js"; export type UniqueDbFundsTeamParam = | { diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index c15fa2c7..c4c1717e 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -10,8 +10,6 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, None, Ok, Option, Result, Some } from "ts-results-es"; import { Service } from "typedi"; -import { UniquePersonParam } from "../person/PersonRepository.js"; -import { SimpleUniqueParam, handleRepositoryError } from "../shared.js"; import { buildFundraisingEntryOrder, buildFundraisingEntryWhere, @@ -21,7 +19,11 @@ import { NotFoundError } from "#error/direct.js"; import { BasicError } from "#error/error.js"; import { SomePrismaError } from "#error/prisma.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - +import { UniquePersonParam } from "#repositories/person/PersonRepository.js"; +import { + SimpleUniqueParam, + handleRepositoryError, +} from "#repositories/shared.js"; const fundraisingEntryBooleanKeys = [] as const; type FundraisingEntryBooleanKey = (typeof fundraisingEntryBooleanKeys)[number]; diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 53f8de97..0e99c6ff 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -3,14 +3,16 @@ import type { SortDirection } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { handleRepositoryError, type RepositoryError } from "../shared.js"; import { buildMarathonOrder, buildMarathonWhere, } from "./marathonRepositoryUtils.js"; import { NotFoundError } from "#error/direct.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - +import { + handleRepositoryError, + type RepositoryError, +} from "#repositories/shared.js"; const marathonBooleanKeys = [] as const; type MarathonBooleanKey = (typeof marathonBooleanKeys)[number]; diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index 1c8aa982..6e807b46 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -3,13 +3,13 @@ import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; +import { NotFoundError } from "#error/direct.js"; +import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, type RepositoryError, type SimpleUniqueParam, -} from "../shared.js"; -import { NotFoundError } from "#error/direct.js"; -import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +} from "#repositories/shared.js"; const membershipBooleanKeys = [] as const; type MembershipBooleanKey = (typeof membershipBooleanKeys)[number]; diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index dad066f4..63c2ae3b 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -16,12 +16,6 @@ import { import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import { - handleRepositoryError, - type RepositoryError, - type SimpleUniqueParam, -} from "../shared.js"; import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; @@ -33,6 +27,12 @@ import { NotFoundError, } from "#error/direct.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; +import { + handleRepositoryError, + type RepositoryError, + type SimpleUniqueParam, +} from "#repositories/shared.js"; const personStringKeys = ["name", "email", "linkblue"] as const; type PersonStringKey = (typeof personStringKeys)[number]; diff --git a/packages/server/src/repositories/person/personModelToResource.ts b/packages/server/src/repositories/person/personModelToResource.ts index 413724d0..b8843946 100644 --- a/packages/server/src/repositories/person/personModelToResource.ts +++ b/packages/server/src/repositories/person/personModelToResource.ts @@ -2,9 +2,9 @@ import type { Person } from "@prisma/client"; import { PersonNode } from "@ukdanceblue/common"; import { AsyncResult } from "ts-results-es"; -import type { RepositoryError } from "../shared.js"; - import type { PersonRepository } from "./PersonRepository.js"; +import type { RepositoryError } from "#repositories/shared.js"; + export function personModelToResource( person: Person, diff --git a/packages/server/src/repositories/team/TeamRepository.ts b/packages/server/src/repositories/team/TeamRepository.ts index be598adf..52d9110f 100644 --- a/packages/server/src/repositories/team/TeamRepository.ts +++ b/packages/server/src/repositories/team/TeamRepository.ts @@ -7,11 +7,11 @@ import type { import { TeamLegacyStatus } from "@ukdanceblue/common"; import { Service } from "typedi"; -import type { UniqueMarathonParam } from "../marathon/MarathonRepository.js"; -import type { SimpleUniqueParam } from "../shared.js"; - import { buildTeamOrder, buildTeamWhere } from "./teamRepositoryUtils.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; +import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; +import type { SimpleUniqueParam } from "#repositories/shared.js"; + const teamBooleanKeys = [] as const; type TeamBooleanKey = (typeof teamBooleanKeys)[number]; diff --git a/packages/server/src/resolvers/AdministrationResolver.ts b/packages/server/src/resolvers/AdministrationResolver.ts index 7c3cbcb3..b72ad345 100644 --- a/packages/server/src/resolvers/AdministrationResolver.ts +++ b/packages/server/src/resolvers/AdministrationResolver.ts @@ -4,7 +4,7 @@ import { join } from "path"; import { AccessControl, AccessLevel } from "@ukdanceblue/common"; import { FieldResolver, ObjectType, Query, Resolver } from "type-graphql"; -import { logDir } from "../environment.js"; +import { logDir } from "#environment"; import { auditLoggerFileName } from "#logging/auditLogging.js"; @ObjectType() diff --git a/packages/server/src/resolvers/ConfigurationResolver.ts b/packages/server/src/resolvers/ConfigurationResolver.ts index 52334a11..ac984afc 100644 --- a/packages/server/src/resolvers/ConfigurationResolver.ts +++ b/packages/server/src/resolvers/ConfigurationResolver.ts @@ -21,15 +21,14 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { auditLogger } from "#logging/auditLogging.js"; +import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; +import { configurationModelToResource } from "#repositories/configuration/configurationModelToResource.js"; import { AbstractGraphQLArrayOkResponse, AbstractGraphQLCreatedResponse, AbstractGraphQLOkResponse, -} from "./ApiResponse.js"; -import { auditLogger } from "#logging/auditLogging.js"; -import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; -import { configurationModelToResource } from "#repositories/configuration/configurationModelToResource.js"; - +} from "#resolvers/ApiResponse.js"; @ObjectType("GetConfigurationByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index dc9da463..9fca3a64 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -25,10 +25,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { auditLogger } from "#logging/auditLogging.js"; import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; @@ -36,7 +32,10 @@ import { deviceModelToResource } from "#repositories/device/deviceModelToResourc import { notificationDeliveryModelToResource } from "#repositories/notificationDelivery/notificationDeliveryModelToResource.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; - +import { + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; @ObjectType("GetDeviceByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/EventResolver.ts b/packages/server/src/resolvers/EventResolver.ts index 2a914f92..cbf796b6 100644 --- a/packages/server/src/resolvers/EventResolver.ts +++ b/packages/server/src/resolvers/EventResolver.ts @@ -27,11 +27,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; import { FileManager } from "#files/FileManager.js"; import { auditLogger } from "#logging/auditLogging.js"; import { EventRepository } from "#repositories/event/EventRepository.js"; @@ -41,7 +36,11 @@ import { } from "#repositories/event/eventModelToResource.js"; import { EventImagesRepository } from "#repositories/event/images/EventImagesRepository.js"; import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; - +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; @ObjectType("GetEventByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index 8cf2f30a..b2d85696 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -22,14 +22,13 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { globalFundraisingAccessParam } from "./FundraisingEntryResolver.js"; import { ConcreteResult } from "#error/result.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; - +import { globalFundraisingAccessParam } from "#resolvers/FundraisingEntryResolver.js"; @InputType() class AssignEntryToPersonInput { diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index 7a84743d..c3ec5503 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -24,14 +24,13 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; - +import { AbstractGraphQLPaginatedResponse } from "#resolvers/ApiResponse.js"; @ArgsType() export class ListFundraisingEntriesArgs extends FilteredListQueryArgs< diff --git a/packages/server/src/resolvers/ImageResolver.ts b/packages/server/src/resolvers/ImageResolver.ts index 2e480e4d..f89032f8 100644 --- a/packages/server/src/resolvers/ImageResolver.ts +++ b/packages/server/src/resolvers/ImageResolver.ts @@ -26,17 +26,16 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; import { FileManager } from "#files/FileManager.js"; import { generateThumbHash } from "#lib/thumbHash.js"; import { auditLogger } from "#logging/auditLogging.js"; import { logger } from "#logging/standardLogging.js"; import { ImageRepository } from "#repositories/image/ImageRepository.js"; import { imageModelToResource } from "#repositories/image/imageModelToResource.js"; - +import { + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; @ObjectType("GetImageByUuidResponse", { implements: AbstractGraphQLOkResponse }) class GetImageByUuidResponse extends AbstractGraphQLOkResponse { diff --git a/packages/server/src/resolvers/LoginState.ts b/packages/server/src/resolvers/LoginState.ts index 0b62cc9e..f3eace55 100644 --- a/packages/server/src/resolvers/LoginState.ts +++ b/packages/server/src/resolvers/LoginState.ts @@ -6,7 +6,7 @@ import { import { Ctx, Field, ObjectType, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; -import * as Context from "./context.js"; +import * as Context from "#resolvers/context.js"; @ObjectType("LoginState") export class LoginState { diff --git a/packages/server/src/resolvers/MarathonHourResolver.ts b/packages/server/src/resolvers/MarathonHourResolver.ts index de833c39..da0db3b8 100644 --- a/packages/server/src/resolvers/MarathonHourResolver.ts +++ b/packages/server/src/resolvers/MarathonHourResolver.ts @@ -23,10 +23,9 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { MarathonHourRepository } from "#repositories/marathonHour/MarathonHourRepository.js"; import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; - +import { AbstractGraphQLPaginatedResponse } from "#resolvers/ApiResponse.js"; @ObjectType("ListMarathonHoursResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index 17349350..c62ee953 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -24,14 +24,13 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; import { ConcreteResult } from "#error/result.js"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; import { marathonHourModelToResource } from "#repositories/marathonHour/marathonHourModelToResource.js"; import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; - +import { AbstractGraphQLPaginatedResponse } from "#resolvers/ApiResponse.js"; @ObjectType("ListMarathonsResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 4e0ea0e7..66906ef9 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -20,22 +20,21 @@ import { Ok } from "ts-results-es"; import { Arg, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; - -import { ConfigurationResolver } from "./ConfigurationResolver.js"; -import { DeviceResolver } from "./DeviceResolver.js"; -import { EventResolver } from "./EventResolver.js"; -// import { FeedResolver } from "./FeedResolver.js"; -import { FundraisingAssignmentResolver } from "./FundraisingAssignmentResolver.js"; -import { FundraisingEntryResolver } from "./FundraisingEntryResolver.js"; -import { ImageResolver } from "./ImageResolver.js"; -import { MarathonHourResolver } from "./MarathonHourResolver.js"; -import { MarathonResolver } from "./MarathonResolver.js"; -import { NotificationResolver } from "./NotificationResolver.js"; -import { PersonResolver } from "./PersonResolver.js"; -import { PointEntryResolver } from "./PointEntryResolver.js"; -import { PointOpportunityResolver } from "./PointOpportunityResolver.js"; -import { TeamResolver } from "./TeamResolver.js"; import { ConcreteResult } from "#error/result.js"; +import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; +import { DeviceResolver } from "#resolvers/DeviceResolver.js"; +import { EventResolver } from "#resolvers/EventResolver.js"; +// import { FeedResolver } from "#resolvers/FeedResolver.js"; +import { FundraisingAssignmentResolver } from "#resolvers/FundraisingAssignmentResolver.js"; +import { FundraisingEntryResolver } from "#resolvers/FundraisingEntryResolver.js"; +import { ImageResolver } from "#resolvers/ImageResolver.js"; +import { MarathonHourResolver } from "#resolvers/MarathonHourResolver.js"; +import { MarathonResolver } from "#resolvers/MarathonResolver.js"; +import { NotificationResolver } from "#resolvers/NotificationResolver.js"; +import { PersonResolver } from "#resolvers/PersonResolver.js"; +import { PointEntryResolver } from "#resolvers/PointEntryResolver.js"; +import { PointOpportunityResolver } from "#resolvers/PointOpportunityResolver.js"; +import { TeamResolver } from "#resolvers/TeamResolver.js"; @Resolver(() => Node) @Service() diff --git a/packages/server/src/resolvers/NotificationResolver.ts b/packages/server/src/resolvers/NotificationResolver.ts index 9c97844f..6109bbcf 100644 --- a/packages/server/src/resolvers/NotificationResolver.ts +++ b/packages/server/src/resolvers/NotificationResolver.ts @@ -28,11 +28,6 @@ import { } from "type-graphql"; import { Inject, Service } from "typedi"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; import { NotificationScheduler } from "#jobs/NotificationScheduler.js"; import { ExpoNotificationProvider } from "#notification/ExpoNotificationProvider.js"; import * as NotificationProviderJs from "#notification/NotificationProvider.js"; @@ -40,7 +35,11 @@ import { NotificationRepository } from "#repositories/notification/NotificationR import { notificationModelToResource } from "#repositories/notification/notificationModelToResource.js"; import { NotificationDeliveryRepository } from "#repositories/notificationDelivery/NotificationDeliveryRepository.js"; import { notificationDeliveryModelToResource } from "#repositories/notificationDelivery/notificationDeliveryModelToResource.js"; - +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; @ObjectType("GetNotificationByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 6e694222..1cfe5bf0 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -32,13 +32,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { AbstractGraphQLPaginatedResponse } from "./ApiResponse.js"; -import { - ListFundraisingEntriesArgs, - ListFundraisingEntriesResponse, - globalFundraisingAccessParam, -} from "./FundraisingEntryResolver.js"; -import type { GraphQLContext } from "./context.js"; import { ConcreteError } from "#error/error.js"; import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; @@ -54,7 +47,13 @@ import { } from "#repositories/membership/membershipModelToResource.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; - +import { AbstractGraphQLPaginatedResponse } from "#resolvers/ApiResponse.js"; +import { + ListFundraisingEntriesArgs, + ListFundraisingEntriesResponse, + globalFundraisingAccessParam, +} from "#resolvers/FundraisingEntryResolver.js"; +import type { GraphQLContext } from "#resolvers/context.js"; @ObjectType("ListPeopleResponse", { implements: AbstractGraphQLPaginatedResponse, diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 521a5cd6..966f8e8f 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -27,11 +27,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; import { NotFoundError } from "#error/direct.js"; import { ConcreteResult } from "#error/result.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; @@ -40,7 +35,11 @@ import { PointEntryRepository } from "#repositories/pointEntry/PointEntryReposit import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; - +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; @ObjectType("GetPointEntryByUuidResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/PointOpportunityResolver.ts b/packages/server/src/resolvers/PointOpportunityResolver.ts index 86c43ae5..530ddced 100644 --- a/packages/server/src/resolvers/PointOpportunityResolver.ts +++ b/packages/server/src/resolvers/PointOpportunityResolver.ts @@ -26,15 +26,14 @@ import { } from "type-graphql"; import { Service } from "typedi"; +import { eventModelToResource } from "#repositories/event/eventModelToResource.js"; +import { PointOpportunityRepository } from "#repositories/pointOpportunity/PointOpportunityRepository.js"; +import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; import { AbstractGraphQLCreatedResponse, AbstractGraphQLOkResponse, AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; -import { eventModelToResource } from "#repositories/event/eventModelToResource.js"; -import { PointOpportunityRepository } from "#repositories/pointOpportunity/PointOpportunityRepository.js"; -import { pointOpportunityModelToResource } from "#repositories/pointOpportunity/pointOpportunityModelToResource.js"; - +} from "#resolvers/ApiResponse.js"; @ObjectType("SinglePointOpportunityResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/TeamResolver.ts b/packages/server/src/resolvers/TeamResolver.ts index 8ec9be8a..14562cbb 100644 --- a/packages/server/src/resolvers/TeamResolver.ts +++ b/packages/server/src/resolvers/TeamResolver.ts @@ -35,17 +35,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { - AbstractGraphQLCreatedResponse, - AbstractGraphQLOkResponse, - AbstractGraphQLPaginatedResponse, -} from "./ApiResponse.js"; -import { - ListFundraisingEntriesArgs, - ListFundraisingEntriesResponse, - globalFundraisingAccessParam, -} from "./FundraisingEntryResolver.js"; -import * as Context from "./context.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; @@ -55,7 +44,17 @@ import { membershipModelToResource } from "#repositories/membership/membershipMo import { pointEntryModelToResource } from "#repositories/pointEntry/pointEntryModelToResource.js"; import { TeamRepository } from "#repositories/team/TeamRepository.js"; import { teamModelToResource } from "#repositories/team/teamModelToResource.js"; - +import { + AbstractGraphQLCreatedResponse, + AbstractGraphQLOkResponse, + AbstractGraphQLPaginatedResponse, +} from "#resolvers/ApiResponse.js"; +import { + ListFundraisingEntriesArgs, + ListFundraisingEntriesResponse, + globalFundraisingAccessParam, +} from "#resolvers/FundraisingEntryResolver.js"; +import * as Context from "#resolvers/context.js"; @ObjectType("SingleTeamResponse", { implements: AbstractGraphQLOkResponse, diff --git a/packages/server/src/resolvers/index.ts b/packages/server/src/resolvers/index.ts index 603b0a5e..50c60b6b 100644 --- a/packages/server/src/resolvers/index.ts +++ b/packages/server/src/resolvers/index.ts @@ -1,2 +1,2 @@ -export { ConfigurationResolver } from "./ConfigurationResolver.js"; -export { ImageResolver } from "./ImageResolver.js"; +export { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; +export { ImageResolver } from "#resolvers/ImageResolver.js"; diff --git a/packages/server/src/routes/api/auth/oidcClient.ts b/packages/server/src/routes/api/auth/oidcClient.ts index d1399e65..d1c6e4fd 100644 --- a/packages/server/src/routes/api/auth/oidcClient.ts +++ b/packages/server/src/routes/api/auth/oidcClient.ts @@ -7,7 +7,7 @@ import { msClientId, msClientSecret, msOidcUrl, -} from "../../../environment.js"; +} from "#environment"; export async function makeOidcClient(req: Request): Promise { const forwardedProto = req.get("x-forwarded-proto"); diff --git a/packages/server/src/routes/api/upload/index.ts b/packages/server/src/routes/api/upload/index.ts index 6c124748..746511ff 100644 --- a/packages/server/src/routes/api/upload/index.ts +++ b/packages/server/src/routes/api/upload/index.ts @@ -5,7 +5,7 @@ import type { File } from "@prisma/client"; import { koaBody } from "koa-body"; import { Container } from "typedi"; -import { maxFileSize } from "../../../environment.js"; +import { maxFileSize } from "#environment"; import { FileManager } from "#files/FileManager.js"; import { generateThumbHash } from "#lib/thumbHash.js"; import { logger } from "#logging/standardLogging.js"; diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index 1ae64239..d6beaa62 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -1,7 +1,7 @@ import { CommitteeIdentifier, CommitteeRole } from "@ukdanceblue/common"; import { Container } from "typedi"; -import { isDevelopment } from "./environment.js"; +import { isDevelopment } from "#environment"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 25ad15e2..00899cec 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -13,11 +13,7 @@ import type { DefaultState } from "koa"; import Koa from "koa"; import { koaBody } from "koa-body"; -import { - applicationHost, - applicationPort, - loggingLevel, -} from "./environment.js"; +import { applicationHost, applicationPort, loggingLevel } from "#environment"; import { logger } from "#logging/logger.js"; import type { GraphQLContext } from "#resolvers/context.js"; import eventsApiRouter from "#routes/api/events/index.js"; diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 6044f4a0..2d82c995 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -23,7 +23,8 @@ "#jobs/*": ["./src/jobs/*"], "#repositories/*": ["./src/repositories/*"], "#resolvers/*": ["./src/resolvers/*"], - "#routes/*": ["./src/routes/*"] + "#routes/*": ["./src/routes/*"], + "#environment": ["./src/environment.ts"] } }, "include": ["src"], From 41ff9d0ba8f6a4b33ed776a9e114863e3cd7eb58 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 04:55:03 +0000 Subject: [PATCH 143/153] Move error types to common --- .../src => common}/lib/error/composite.ts | 0 .../src => common}/lib/error/control.ts | 0 .../src => common}/lib/error/direct.ts | 0 .../{server/src => common}/lib/error/error.ts | 0 .../{server/src => common}/lib/error/http.ts | 0 packages/common/lib/error/index.ts | 7 +++ .../src => common}/lib/error/option.ts | 0 .../src => common}/lib/error/result.ts | 10 ---- packages/common/package.json | 5 ++ packages/server/src/jobs/syncDbFunds.ts | 5 +- packages/server/src/lib/error/prisma.ts | 3 +- packages/server/src/lib/error/zod.ts | 3 +- packages/server/src/lib/formatError.ts | 2 +- .../src/lib/fundraising/DbFundsProvider.ts | 13 +++-- .../lib/fundraising/FundraisingProvider.ts | 2 +- packages/server/src/lib/graphqlSchema.ts | 2 +- .../committee/CommitteeRepository.ts | 5 +- .../repositories/device/DeviceRepository.ts | 2 +- .../fundraising/DBFundsRepository.ts | 26 ++++----- .../fundraising/FundraisingRepository.ts | 54 ++++++------------- .../fundraisingEntryRepositoryUtils.ts | 3 +- .../marathon/MarathonRepository.ts | 2 +- .../membership/MembershipRepository.ts | 2 +- .../repositories/person/PersonRepository.ts | 12 ++--- .../person/personRepositoryUtils.ts | 3 +- packages/server/src/repositories/shared.ts | 8 ++- .../server/src/resolvers/DeviceResolver.ts | 2 +- .../FundraisingAssignmentResolver.ts | 2 +- .../src/resolvers/FundraisingEntryResolver.ts | 2 +- .../server/src/resolvers/MarathonResolver.ts | 2 +- .../src/resolvers/MembershipResolver.ts | 2 +- packages/server/src/resolvers/NodeResolver.ts | 2 +- .../server/src/resolvers/PersonResolver.ts | 3 +- .../src/resolvers/PointEntryResolver.ts | 3 +- packages/server/src/resolvers/context.ts | 4 +- 35 files changed, 77 insertions(+), 114 deletions(-) rename packages/{server/src => common}/lib/error/composite.ts (100%) rename packages/{server/src => common}/lib/error/control.ts (100%) rename packages/{server/src => common}/lib/error/direct.ts (100%) rename packages/{server/src => common}/lib/error/error.ts (100%) rename packages/{server/src => common}/lib/error/http.ts (100%) create mode 100644 packages/common/lib/error/index.ts rename packages/{server/src => common}/lib/error/option.ts (100%) rename packages/{server/src => common}/lib/error/result.ts (56%) diff --git a/packages/server/src/lib/error/composite.ts b/packages/common/lib/error/composite.ts similarity index 100% rename from packages/server/src/lib/error/composite.ts rename to packages/common/lib/error/composite.ts diff --git a/packages/server/src/lib/error/control.ts b/packages/common/lib/error/control.ts similarity index 100% rename from packages/server/src/lib/error/control.ts rename to packages/common/lib/error/control.ts diff --git a/packages/server/src/lib/error/direct.ts b/packages/common/lib/error/direct.ts similarity index 100% rename from packages/server/src/lib/error/direct.ts rename to packages/common/lib/error/direct.ts diff --git a/packages/server/src/lib/error/error.ts b/packages/common/lib/error/error.ts similarity index 100% rename from packages/server/src/lib/error/error.ts rename to packages/common/lib/error/error.ts diff --git a/packages/server/src/lib/error/http.ts b/packages/common/lib/error/http.ts similarity index 100% rename from packages/server/src/lib/error/http.ts rename to packages/common/lib/error/http.ts diff --git a/packages/common/lib/error/index.ts b/packages/common/lib/error/index.ts new file mode 100644 index 00000000..5bceea01 --- /dev/null +++ b/packages/common/lib/error/index.ts @@ -0,0 +1,7 @@ +export * from "./composite.js"; +export * from "./control.js"; +export * from "./direct.js"; +export * from "./error.js"; +export * from "./http.js"; +export * from "./option.js"; +export * from "./result.js"; diff --git a/packages/server/src/lib/error/option.ts b/packages/common/lib/error/option.ts similarity index 100% rename from packages/server/src/lib/error/option.ts rename to packages/common/lib/error/option.ts diff --git a/packages/server/src/lib/error/result.ts b/packages/common/lib/error/result.ts similarity index 56% rename from packages/server/src/lib/error/result.ts rename to packages/common/lib/error/result.ts index bc3a7570..7ca66799 100644 --- a/packages/server/src/lib/error/result.ts +++ b/packages/common/lib/error/result.ts @@ -1,16 +1,6 @@ import type { Result } from "ts-results-es"; import type { ConcreteError, JsError, UnknownError } from "./error.js"; -import type { HttpError } from "./http.js"; -import type { PrismaError } from "./prisma.js"; -import type { ZodError } from "./zod.js"; - -export type ConcreteErrorTypes = - | UnknownError - | JsError - | HttpError - | PrismaError - | ZodError; export type ConcreteResult = Result< T, diff --git a/packages/common/package.json b/packages/common/package.json index 69824675..38dbd465 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -19,6 +19,11 @@ "node": null, "default": "./dist/client-parsers/index.js" }, + "./error": { + "types": "./dist/error/index.d.ts", + "node": "./dist/error/index.js", + "default": null + }, "./graphql-client-admin": { "node": null, "react-native": null, diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index da8fc272..43b71090 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -1,11 +1,10 @@ import type { MarathonYearString } from "@ukdanceblue/common"; +import type { NotFoundError } from "@ukdanceblue/common/error"; +import { CompositeError, toBasicError } from "@ukdanceblue/common/error"; import Cron from "croner"; import { Err, None, Ok, type Result } from "ts-results-es"; import { Container } from "typedi"; -import { CompositeError } from "#error/composite.js"; -import type { NotFoundError } from "#error/direct.js"; -import { toBasicError } from "#error/error.js"; import type { PrismaError } from "#error/prisma.js"; import { DBFundsFundraisingProvider, diff --git a/packages/server/src/lib/error/prisma.ts b/packages/server/src/lib/error/prisma.ts index 3b583365..4915e1ee 100644 --- a/packages/server/src/lib/error/prisma.ts +++ b/packages/server/src/lib/error/prisma.ts @@ -5,11 +5,10 @@ import { PrismaClientUnknownRequestError, PrismaClientValidationError, } from "@prisma/client/runtime/library"; +import { ConcreteError } from "@ukdanceblue/common/error"; import type { Option } from "ts-results-es"; import { None, Some } from "ts-results-es"; -import { ConcreteError } from "./error.js"; - type RawPrismaError = | PrismaClientKnownRequestError | PrismaClientUnknownRequestError diff --git a/packages/server/src/lib/error/zod.ts b/packages/server/src/lib/error/zod.ts index 3494a000..b93c57e3 100644 --- a/packages/server/src/lib/error/zod.ts +++ b/packages/server/src/lib/error/zod.ts @@ -1,7 +1,6 @@ +import { ConcreteError } from "@ukdanceblue/common/error"; import type { ZodError as RawZodError } from "zod"; -import { ConcreteError } from "./error.js"; - const ZodErrorTag = Symbol("ZodError"); type ZodErrorTag = typeof ZodErrorTag; export class ZodError extends ConcreteError { diff --git a/packages/server/src/lib/formatError.ts b/packages/server/src/lib/formatError.ts index f1b4f76f..87b8078a 100644 --- a/packages/server/src/lib/formatError.ts +++ b/packages/server/src/lib/formatError.ts @@ -9,12 +9,12 @@ import { UnionValidationError, isErrorCode, } from "@ukdanceblue/common"; +import type { ConcreteError } from "@ukdanceblue/common/error"; import type { GraphQLFormattedError } from "graphql"; import { GraphQLError } from "graphql"; import jwt from "jsonwebtoken"; import type { Writable } from "utility-types"; -import type { ConcreteError } from "#error/error.js"; export interface DbGraphQLFormattedErrorExtensions extends Omit { diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 584ca514..368133ed 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -1,4 +1,12 @@ import type { MarathonYearString } from "@ukdanceblue/common"; +import { + TimeoutError, + BasicError, + toBasicError, + HttpError, + optionOf, + ConcreteResult, +} from "@ukdanceblue/common/error"; import { DateTime } from "luxon"; import { Err, Ok } from "ts-results-es"; import { Inject, Service } from "typedi"; @@ -10,11 +18,6 @@ import type { FundraisingTeam, } from "./FundraisingProvider.js"; import { dbFundsApiKeyToken, dbFundsApiOriginToken } from "#environment"; -import { TimeoutError } from "#error/direct.js"; -import { BasicError, toBasicError } from "#error/error.js"; -import { HttpError } from "#error/http.js"; -import { optionOf } from "#error/option.js"; -import { ConcreteResult } from "#error/result.js"; import { ZodError } from "#error/zod.js"; const dbFundsFundraisingTeamSchema = z.object({ diff --git a/packages/server/src/lib/fundraising/FundraisingProvider.ts b/packages/server/src/lib/fundraising/FundraisingProvider.ts index 80de16e9..35b1f6ea 100644 --- a/packages/server/src/lib/fundraising/FundraisingProvider.ts +++ b/packages/server/src/lib/fundraising/FundraisingProvider.ts @@ -1,8 +1,8 @@ import type { MarathonYearString } from "@ukdanceblue/common"; +import type { ConcreteResult } from "@ukdanceblue/common/error"; import type { DateTime } from "luxon"; import type { Option } from "ts-results-es"; -import type { ConcreteResult } from "#error/result.js"; export interface FundraisingTeam { name: string; diff --git a/packages/server/src/lib/graphqlSchema.ts b/packages/server/src/lib/graphqlSchema.ts index 6256ec08..630aa621 100644 --- a/packages/server/src/lib/graphqlSchema.ts +++ b/packages/server/src/lib/graphqlSchema.ts @@ -1,12 +1,12 @@ import { fileURLToPath } from "url"; +import { ConcreteError, toBasicError } from "@ukdanceblue/common/error"; import { Result } from "ts-results-es"; import type { MiddlewareFn } from "type-graphql"; import { buildSchema } from "type-graphql"; import { Container } from "typedi"; import { CatchableConcreteError } from "./formatError.js"; -import { ConcreteError, toBasicError } from "#error/error.js"; import { logger } from "#logging/logger.js"; import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; import { DeviceResolver } from "#resolvers/DeviceResolver.js"; diff --git a/packages/server/src/repositories/committee/CommitteeRepository.ts b/packages/server/src/repositories/committee/CommitteeRepository.ts index d0ecf7b1..03b80911 100644 --- a/packages/server/src/repositories/committee/CommitteeRepository.ts +++ b/packages/server/src/repositories/committee/CommitteeRepository.ts @@ -4,6 +4,7 @@ import { CommitteeRole, SortDirection, } from "@ukdanceblue/common"; +import { CompositeError , InvariantError, NotFoundError , toBasicError } from "@ukdanceblue/common/error"; import { Err, None, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; @@ -12,9 +13,6 @@ import { buildCommitteeOrder, buildCommitteeWhere, } from "./committeeRepositoryUtils.js"; -import { CompositeError } from "#error/composite.js"; -import { InvariantError, NotFoundError } from "#error/direct.js"; -import { toBasicError } from "#error/error.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; @@ -25,7 +23,6 @@ import { handleRepositoryError, } from "#repositories/shared.js"; - // Make sure that we are exporting a description for every committee CommitteeDescriptions[ "" as CommitteeIdentifier diff --git a/packages/server/src/repositories/device/DeviceRepository.ts b/packages/server/src/repositories/device/DeviceRepository.ts index 0d4ea7df..3dbaaabe 100644 --- a/packages/server/src/repositories/device/DeviceRepository.ts +++ b/packages/server/src/repositories/device/DeviceRepository.ts @@ -1,11 +1,11 @@ import type { Person } from "@prisma/client"; import { PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; +import { NotFoundError } from "@ukdanceblue/common/error"; import { Err, Result } from "ts-results-es"; import { Service } from "typedi"; import { buildDeviceOrder, buildDeviceWhere } from "./deviceRepositoryUtils.js"; -import { NotFoundError } from "#error/direct.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { NotificationAudience } from "#notification/NotificationProvider.js"; diff --git a/packages/server/src/repositories/fundraising/DBFundsRepository.ts b/packages/server/src/repositories/fundraising/DBFundsRepository.ts index beb780b1..32716893 100644 --- a/packages/server/src/repositories/fundraising/DBFundsRepository.ts +++ b/packages/server/src/repositories/fundraising/DBFundsRepository.ts @@ -1,16 +1,18 @@ import { DBFundsTeam, Prisma, PrismaClient, Team } from "@prisma/client"; + +import { + CompositeError, + NotFoundError, + BasicError, +} from "@ukdanceblue/common/error"; import { DateTime } from "luxon"; import { Err, None, Ok, Option, Result } from "ts-results-es"; import { Service } from "typedi"; - -import { CompositeError } from "#error/composite.js"; -import { NotFoundError } from "#error/direct.js"; -import { BasicError } from "#error/error.js"; -import { PrismaError, SomePrismaError } from "#error/prisma.js"; import { logger } from "#logging/standardLogging.js"; import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; import { + RepositoryError, SimpleUniqueParam, handleRepositoryError, } from "#repositories/shared.js"; @@ -46,13 +48,7 @@ export class DBFundsRepository { amount: number; }[] ): Promise< - Result< - None, - | PrismaError - | NotFoundError - | CompositeError - | BasicError - > + Result> > { try { let marathonId: number; @@ -196,7 +192,7 @@ export class DBFundsRepository { async getTeamsForDbFundsTeam( dbFundsTeamParam: UniqueDbFundsTeamParam - ): Promise> { + ): Promise> { try { const team = await this.prisma.dBFundsTeam.findUnique({ where: @@ -226,7 +222,7 @@ export class DBFundsRepository { | { dbNum: number; } - ): Promise> { + ): Promise> { try { const team = await this.prisma.team.findUnique({ where: teamParam, @@ -263,7 +259,7 @@ export class DBFundsRepository { byDbNum?: number; byName?: string; onlyActive?: boolean; - }): Promise> { + }): Promise> { try { return Ok( await this.prisma.dBFundsTeam.findMany({ diff --git a/packages/server/src/repositories/fundraising/FundraisingRepository.ts b/packages/server/src/repositories/fundraising/FundraisingRepository.ts index c4c1717e..8489070e 100644 --- a/packages/server/src/repositories/fundraising/FundraisingRepository.ts +++ b/packages/server/src/repositories/fundraising/FundraisingRepository.ts @@ -7,20 +7,18 @@ import { PrismaClient, } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; + +import { ActionDeniedError, NotFoundError } from "@ukdanceblue/common/error"; import { Err, None, Ok, Option, Result, Some } from "ts-results-es"; import { Service } from "typedi"; - import { buildFundraisingEntryOrder, buildFundraisingEntryWhere, } from "./fundraisingEntryRepositoryUtils.js"; -import { ActionDeniedError } from "#error/control.js"; -import { NotFoundError } from "#error/direct.js"; -import { BasicError } from "#error/error.js"; -import { SomePrismaError } from "#error/prisma.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { UniquePersonParam } from "#repositories/person/PersonRepository.js"; import { + RepositoryError, SimpleUniqueParam, handleRepositoryError, } from "#repositories/shared.js"; @@ -81,7 +79,7 @@ export class FundraisingEntryRepository { ): Promise< Result< FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry }, - SomePrismaError | BasicError | NotFoundError + RepositoryError > > { try { @@ -104,9 +102,7 @@ export class FundraisingEntryRepository { async findAssignmentByUnique( param: FundraisingAssignmentUniqueParam - ): Promise< - Result - > { + ): Promise> { try { const row = await this.prisma.fundraisingAssignment.findUnique({ where: param, @@ -122,12 +118,7 @@ export class FundraisingEntryRepository { async getAssignmentsForEntry( param: FundraisingEntryUniqueParam - ): Promise< - Result< - readonly FundraisingAssignment[], - SomePrismaError | BasicError | NotFoundError - > - > { + ): Promise> { try { const entry = await this.prisma.fundraisingEntry.findUnique({ where: param, @@ -166,7 +157,7 @@ export class FundraisingEntryRepository { readonly (FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry; })[], - SomePrismaError | BasicError | ActionDeniedError + RepositoryError | ActionDeniedError > > { try { @@ -229,9 +220,7 @@ export class FundraisingEntryRepository { filters, }: { filters?: readonly FundraisingEntryFilters[] | undefined | null; - }): Promise< - Result - > { + }): Promise> { try { const where = buildFundraisingEntryWhere(filters); if (where.isErr()) { @@ -248,7 +237,7 @@ export class FundraisingEntryRepository { async deleteEntry( param: FundraisingEntryUniqueParam - ): Promise, SomePrismaError | BasicError>> { + ): Promise, RepositoryError>> { try { return Ok( Some(await this.prisma.fundraisingEntry.delete({ where: param })) @@ -270,10 +259,7 @@ export class FundraisingEntryRepository { personParam: SimpleUniqueParam, { amount }: { amount: number } ): Promise< - Result< - FundraisingAssignment, - SomePrismaError | BasicError | NotFoundError | ActionDeniedError - > + Result > { try { const entry = await this.findEntryByUnique(entryParam); @@ -311,9 +297,7 @@ export class FundraisingEntryRepository { async deleteAssignment( assignmentParam: FundraisingAssignmentUniqueParam - ): Promise< - Result - > { + ): Promise> { try { return Ok( await this.prisma.fundraisingAssignment.delete({ @@ -329,10 +313,7 @@ export class FundraisingEntryRepository { assignmentParam: FundraisingAssignmentUniqueParam, { amount }: { amount: number } ): Promise< - Result< - FundraisingAssignment, - SomePrismaError | BasicError | NotFoundError | ActionDeniedError - > + Result > { try { const assignment = await this.prisma.fundraisingAssignment.findUnique({ @@ -383,7 +364,7 @@ export class FundraisingEntryRepository { async getPersonForAssignment( assignmentParam: FundraisingAssignmentUniqueParam - ): Promise> { + ): Promise> { try { const assignment = await this.prisma.fundraisingAssignment.findUnique({ where: assignmentParam, @@ -405,7 +386,7 @@ export class FundraisingEntryRepository { FundraisingEntry & { dbFundsEntry: DBFundsFundraisingEntry; }, - SomePrismaError | BasicError | NotFoundError + RepositoryError > > { try { @@ -432,12 +413,7 @@ export class FundraisingEntryRepository { async getAssignmentsForPerson( personParam: UniquePersonParam - ): Promise< - Result< - readonly FundraisingAssignment[], - SomePrismaError | BasicError | NotFoundError - > - > { + ): Promise> { try { const assignments = await this.prisma.fundraisingAssignment.findMany({ where: { person: personParam }, diff --git a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts index 9314c520..32345d5f 100644 --- a/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts +++ b/packages/server/src/repositories/fundraising/fundraisingEntryRepositoryUtils.ts @@ -1,5 +1,6 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import { ActionDeniedError } from "@ukdanceblue/common/error"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; @@ -7,7 +8,6 @@ import type { FundraisingEntryFilters, FundraisingEntryOrderKeys, } from "./FundraisingRepository.js"; -import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, numericFilterToPrisma, @@ -15,7 +15,6 @@ import { stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - export function buildFundraisingEntryOrder( order: | readonly [key: FundraisingEntryOrderKeys, sort: SortDirection][] diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 0e99c6ff..581bf3b8 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -1,5 +1,6 @@ import { Marathon, MarathonHour, Prisma, PrismaClient } from "@prisma/client"; import type { SortDirection } from "@ukdanceblue/common"; +import { NotFoundError } from "@ukdanceblue/common/error"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; @@ -7,7 +8,6 @@ import { buildMarathonOrder, buildMarathonWhere, } from "./marathonRepositoryUtils.js"; -import { NotFoundError } from "#error/direct.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, diff --git a/packages/server/src/repositories/membership/MembershipRepository.ts b/packages/server/src/repositories/membership/MembershipRepository.ts index 6e807b46..696b3bd5 100644 --- a/packages/server/src/repositories/membership/MembershipRepository.ts +++ b/packages/server/src/repositories/membership/MembershipRepository.ts @@ -1,9 +1,9 @@ import { Membership, Person, PrismaClient, Team } from "@prisma/client"; import { CommitteeRole, MembershipPositionType } from "@ukdanceblue/common"; +import { NotFoundError } from "@ukdanceblue/common/error"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; -import { NotFoundError } from "#error/direct.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import { handleRepositoryError, diff --git a/packages/server/src/repositories/person/PersonRepository.ts b/packages/server/src/repositories/person/PersonRepository.ts index 63c2ae3b..78665d20 100644 --- a/packages/server/src/repositories/person/PersonRepository.ts +++ b/packages/server/src/repositories/person/PersonRepository.ts @@ -13,19 +13,17 @@ import { TeamLegacyStatus, TeamType, } from "@ukdanceblue/common"; +import { ActionDeniedError , + InvalidArgumentError, + InvariantError, + NotFoundError, +} from "@ukdanceblue/common/error"; import { Err, Ok, Result } from "ts-results-es"; import { Service } from "typedi"; - import { buildPersonOrder, buildPersonWhere } from "./personRepositoryUtils.js"; import { findPersonForLogin } from "#auth/findPersonForLogin.js"; -import { ActionDeniedError } from "#error/control.js"; -import { - InvalidArgumentError, - InvariantError, - NotFoundError, -} from "#error/direct.js"; import type { FilterItems } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; import type { UniqueMarathonParam } from "#repositories/marathon/MarathonRepository.js"; import { diff --git a/packages/server/src/repositories/person/personRepositoryUtils.ts b/packages/server/src/repositories/person/personRepositoryUtils.ts index 60c9bbc8..cf0c3413 100644 --- a/packages/server/src/repositories/person/personRepositoryUtils.ts +++ b/packages/server/src/repositories/person/personRepositoryUtils.ts @@ -1,16 +1,15 @@ import type { Prisma } from "@prisma/client"; import { SortDirection } from "@ukdanceblue/common"; +import { ActionDeniedError } from "@ukdanceblue/common/error"; import type { Result } from "ts-results-es"; import { Err, Ok } from "ts-results-es"; import type { PersonFilters, PersonOrderKeys } from "./PersonRepository.js"; -import { ActionDeniedError } from "#error/control.js"; import { dateFilterToPrisma, stringFilterToPrisma, } from "#lib/prisma-utils/gqlFilterToPrismaFilter.js"; - export function buildPersonOrder( order: | readonly [key: PersonOrderKeys, sort: SortDirection][] diff --git a/packages/server/src/repositories/shared.ts b/packages/server/src/repositories/shared.ts index ee216399..6648bd16 100644 --- a/packages/server/src/repositories/shared.ts +++ b/packages/server/src/repositories/shared.ts @@ -1,10 +1,8 @@ +import type { NotFoundError, BasicError } from "@ukdanceblue/common/error"; +import { toBasicError } from "@ukdanceblue/common/error"; import { Err } from "ts-results-es"; - -import type { NotFoundError } from "#error/direct.js"; -import type { BasicError } from "#error/error.js"; -import { toBasicError } from "#error/error.js"; -import type { SomePrismaError } from "#error/prisma.js"; import { toPrismaError } from "#error/prisma.js"; +import type { SomePrismaError } from "#error/prisma.js"; export type SimpleUniqueParam = { id: number } | { uuid: string }; export type RepositoryError = SomePrismaError | BasicError | NotFoundError; diff --git a/packages/server/src/resolvers/DeviceResolver.ts b/packages/server/src/resolvers/DeviceResolver.ts index 9fca3a64..3235aacd 100644 --- a/packages/server/src/resolvers/DeviceResolver.ts +++ b/packages/server/src/resolvers/DeviceResolver.ts @@ -9,6 +9,7 @@ import { PersonNode, SortDirection, } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { Arg, Args, @@ -25,7 +26,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { auditLogger } from "#logging/auditLogging.js"; import { DeviceRepository } from "#repositories/device/DeviceRepository.js"; import { deviceModelToResource } from "#repositories/device/deviceModelToResource.js"; diff --git a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts index b2d85696..79f52f37 100644 --- a/packages/server/src/resolvers/FundraisingAssignmentResolver.ts +++ b/packages/server/src/resolvers/FundraisingAssignmentResolver.ts @@ -10,6 +10,7 @@ import { MembershipPositionType, PersonNode, } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { Arg, Field, @@ -22,7 +23,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; import { fundraisingAssignmentModelToNode } from "#repositories/fundraising/fundraisingAssignmentModelToNode.js"; import { fundraisingEntryModelToNode } from "#repositories/fundraising/fundraisingEntryModelToNode.js"; diff --git a/packages/server/src/resolvers/FundraisingEntryResolver.ts b/packages/server/src/resolvers/FundraisingEntryResolver.ts index c3ec5503..1dc9cad0 100644 --- a/packages/server/src/resolvers/FundraisingEntryResolver.ts +++ b/packages/server/src/resolvers/FundraisingEntryResolver.ts @@ -11,6 +11,7 @@ import { MembershipPositionType, SortDirection, } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { Arg, Args, @@ -24,7 +25,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; import { FundraisingEntryRepository } from "#repositories/fundraising/FundraisingRepository.js"; diff --git a/packages/server/src/resolvers/MarathonResolver.ts b/packages/server/src/resolvers/MarathonResolver.ts index c62ee953..3e1c5926 100644 --- a/packages/server/src/resolvers/MarathonResolver.ts +++ b/packages/server/src/resolvers/MarathonResolver.ts @@ -8,6 +8,7 @@ import { SortDirection, TeamNode, } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { DateTimeISOResolver, VoidResolver } from "graphql-scalars"; import { Arg, @@ -24,7 +25,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; import { marathonModelToResource } from "#repositories/marathon/marathonModelToResource.js"; diff --git a/packages/server/src/resolvers/MembershipResolver.ts b/packages/server/src/resolvers/MembershipResolver.ts index c10ac41b..abf4cdc0 100644 --- a/packages/server/src/resolvers/MembershipResolver.ts +++ b/packages/server/src/resolvers/MembershipResolver.ts @@ -1,8 +1,8 @@ import { MembershipNode, PersonNode, TeamNode } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { FieldResolver, Resolver, Root } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { MembershipRepository } from "#repositories/membership/MembershipRepository.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; diff --git a/packages/server/src/resolvers/NodeResolver.ts b/packages/server/src/resolvers/NodeResolver.ts index 66906ef9..2097622d 100644 --- a/packages/server/src/resolvers/NodeResolver.ts +++ b/packages/server/src/resolvers/NodeResolver.ts @@ -16,11 +16,11 @@ import { PointOpportunityNode, TeamNode, } from "@ukdanceblue/common"; +import { ConcreteResult } from "@ukdanceblue/common/error"; import { Ok } from "ts-results-es"; import { Arg, Query, Resolver } from "type-graphql"; import { Service } from "typedi"; -import { ConcreteResult } from "#error/result.js"; import { ConfigurationResolver } from "#resolvers/ConfigurationResolver.js"; import { DeviceResolver } from "#resolvers/DeviceResolver.js"; import { EventResolver } from "#resolvers/EventResolver.js"; diff --git a/packages/server/src/resolvers/PersonResolver.ts b/packages/server/src/resolvers/PersonResolver.ts index 1cfe5bf0..9ef056b0 100644 --- a/packages/server/src/resolvers/PersonResolver.ts +++ b/packages/server/src/resolvers/PersonResolver.ts @@ -14,6 +14,7 @@ import { PersonNode, SortDirection, } from "@ukdanceblue/common"; +import { ConcreteError , ConcreteResult } from "@ukdanceblue/common/error"; import { EmailAddressResolver } from "graphql-scalars"; import { Ok, Result } from "ts-results-es"; import { @@ -32,8 +33,6 @@ import { } from "type-graphql"; import { Container, Service } from "typedi"; -import { ConcreteError } from "#error/error.js"; -import { ConcreteResult } from "#error/result.js"; import { CatchableConcreteError } from "#lib/formatError.js"; import { auditLogger } from "#logging/auditLogging.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; diff --git a/packages/server/src/resolvers/PointEntryResolver.ts b/packages/server/src/resolvers/PointEntryResolver.ts index 966f8e8f..7e782b85 100644 --- a/packages/server/src/resolvers/PointEntryResolver.ts +++ b/packages/server/src/resolvers/PointEntryResolver.ts @@ -10,6 +10,7 @@ import { SortDirection, TeamNode, } from "@ukdanceblue/common"; +import { NotFoundError , ConcreteResult } from "@ukdanceblue/common/error"; import { Err } from "ts-results-es"; import { Arg, @@ -27,8 +28,6 @@ import { } from "type-graphql"; import { Service } from "typedi"; -import { NotFoundError } from "#error/direct.js"; -import { ConcreteResult } from "#error/result.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; import { PointEntryRepository } from "#repositories/pointEntry/PointEntryRepository.js"; diff --git a/packages/server/src/resolvers/context.ts b/packages/server/src/resolvers/context.ts index 71d34541..2eaaf86d 100644 --- a/packages/server/src/resolvers/context.ts +++ b/packages/server/src/resolvers/context.ts @@ -12,13 +12,13 @@ import { DbRole, roleToAccessLevel, } from "@ukdanceblue/common"; +import { NotFoundError } from "@ukdanceblue/common/error"; +import type { ConcreteResult } from "@ukdanceblue/common/error"; import type { DefaultState } from "koa"; import { Ok } from "ts-results-es"; import { Container } from "typedi"; import { defaultAuthorization, parseUserJwt } from "#auth/index.js"; -import { NotFoundError } from "#error/direct.js"; -import type { ConcreteResult } from "#error/result.js"; import { logger } from "#logging/logger.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; import { personModelToResource } from "#repositories/person/personModelToResource.js"; From a86042226a7576d0946125e08ed65a32462b02b8 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Tue, 2 Jul 2024 05:36:32 +0000 Subject: [PATCH 144/153] Update TypeScript dependency to version 5.5.3 --- package.json | 2 +- packages/common/package.json | 2 +- packages/mobile/package.json | 2 +- packages/portal/package.json | 2 +- packages/server/package.json | 2 +- yarn.lock | 26 +++++++++++++------------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index a3f69a28..2b2c262c 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "graphql": "^16.8.1", "graphql-scalars": "^1.23.0", "prettier": "^3.2.5", - "typescript": "^5.4.3", + "typescript": "^5.5.3", "vitest": "^1.4.0" }, "workspaces": [ diff --git a/packages/common/package.json b/packages/common/package.json index 38dbd465..05bff70a 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -63,7 +63,7 @@ "jest": "^29.5.0", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", - "typescript": "^5.4.3", + "typescript": "^5.5.3", "vitest": "^1.4.0" }, "peerDependencies": { diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 5d891e28..2eba830f 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -105,7 +105,7 @@ "reflect-metadata": "^0.1.13", "type-graphql": "^2.0.0-beta.3", "typedi": "^0.10.0", - "typescript": "^5.4.3", + "typescript": "^5.5.3", "urql": "^4.0.6", "utility-types": "^3.10.0", "validator": "^13.9.0" diff --git a/packages/portal/package.json b/packages/portal/package.json index e401b016..9b6b9a9e 100644 --- a/packages/portal/package.json +++ b/packages/portal/package.json @@ -41,7 +41,7 @@ "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react-swc": "^3.3.2", - "typescript": "^5.4.3", + "typescript": "^5.5.3", "vite": "^4.4.5" }, "packageManager": "yarn@4.1.1+sha256.f3cc0eda8e5560e529c7147565b30faa43b4e472d90e8634d7134a37c7f59781" diff --git a/packages/server/package.json b/packages/server/package.json index 692ecf36..5eab3a4c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -65,7 +65,7 @@ "ts-results-es": "^4.2.0", "type-graphql": "^2.0.0-beta.3", "typedi": "^0.10.0", - "typescript": "^5.4.3", + "typescript": "^5.5.3", "utility-types": "^3.10.0", "validator": "^13.9.0", "winston": "^3.8.2", diff --git a/yarn.lock b/yarn.lock index a61ce48e..5604f89f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8363,7 +8363,7 @@ __metadata: ts-jest: "npm:^29.1.0" ts-node: "npm:^10.9.1" ts-results-es: "npm:^4.2.0" - typescript: "npm:^5.4.3" + typescript: "npm:^5.5.3" vitest: "npm:^1.4.0" peerDependencies: class-validator: 0.14.0 @@ -8501,7 +8501,7 @@ __metadata: ts-node: "npm:^10.9.1" type-graphql: "npm:^2.0.0-beta.3" typedi: "npm:^0.10.0" - typescript: "npm:^5.4.3" + typescript: "npm:^5.5.3" urql: "npm:^4.0.6" utility-types: "npm:^3.10.0" validator: "npm:^13.9.0" @@ -8539,7 +8539,7 @@ __metadata: graphql: "npm:^16.8.1" graphql-scalars: "npm:^1.23.0" prettier: "npm:^3.2.5" - typescript: "npm:^5.4.3" + typescript: "npm:^5.5.3" vitest: "npm:^1.4.0" languageName: unknown linkType: soft @@ -8573,7 +8573,7 @@ __metadata: thumbhash: "npm:^0.1.1" type-graphql: "npm:^2.0.0-beta.3" typedi: "npm:^0.10.0" - typescript: "npm:^5.4.3" + typescript: "npm:^5.5.3" urql: "npm:^4.0.5" use-debounce: "npm:^10.0.0" utility-types: "npm:^3.10.0" @@ -8635,7 +8635,7 @@ __metadata: ts-results-es: "npm:^4.2.0" type-graphql: "npm:^2.0.0-beta.3" typedi: "npm:^0.10.0" - typescript: "npm:^5.4.3" + typescript: "npm:^5.5.3" utility-types: "npm:^3.10.0" validator: "npm:^13.9.0" vitest: "npm:^1.4.0" @@ -26032,23 +26032,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.4.3": - version: 5.4.3 - resolution: "typescript@npm:5.4.3" +"typescript@npm:^5.5.3": + version: 5.5.3 + resolution: "typescript@npm:5.5.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/de4c69f49a7ad4b1ea66a6dcc8b055ac34eb56af059a069d8988dd811c5e649be07e042e5bf573e8d0ac3ec2f30e6c999aa651cd09f6e9cbc6113749e8b6be20 + checksum: 10/11a867312419ed497929aafd2f1d28b2cd41810a5eb6c6e9e169559112e9ea073d681c121a29102e67cd4478d0a4ae37a306a5800f3717f59c4337e6a9bd5e8d languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin": - version: 5.4.3 - resolution: "typescript@patch:typescript@npm%3A5.4.3#optional!builtin::version=5.4.3&hash=5adc0c" +"typescript@patch:typescript@npm%3A^5.5.3#optional!builtin": + version: 5.5.3 + resolution: "typescript@patch:typescript@npm%3A5.5.3#optional!builtin::version=5.5.3&hash=5adc0c" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/5aedd97595582b08aadb8a70e8e3ddebaf5a9c1e5ad4d6503c2fcfc15329b5cf8d01145b09913e9555683ac16c5123a96be32b6d72614098ebd42df520eed9b1 + checksum: 10/b61b8bb4b4d6a8a00f9d5f931f8c67070eed6ad11feabf4c41744a326987080bfc806a621596c70fbf2e5974eca3ed65bafeeeb22a078071bdfb51d8abd7c013 languageName: node linkType: hard From 1509414226bb27b10084489dedf8246aa000bce7 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 10 Jul 2024 20:43:48 +0000 Subject: [PATCH 145/153] Updates to server/docker config and startup --- .devcontainer/Dockerfile | 4 +- .devcontainer/devcontainer.json | 5 - .vscode/extensions.json | 25 +++++ compose.yaml | 22 +++-- package.json | 1 + packages/portal/Dockerfile | 8 +- packages/server/.env.example | 5 - packages/server/Dockerfile | 8 +- packages/server/package.json | 5 +- .../20240710193233_job_state/migration.sql | 7 ++ packages/server/prisma/schema.prisma | 7 ++ packages/server/src/environment.ts | 35 +------ packages/server/src/jobs/fetchPushReceipts.ts | 9 ++ .../server/src/jobs/garbageCollectLogins.ts | 9 ++ packages/server/src/jobs/index.ts | 9 +- packages/server/src/jobs/syncDbFunds.ts | 9 ++ packages/server/src/lib/files/FileManager.ts | 2 - packages/server/src/repositories/JobState.ts | 34 +++++++ .../marathon/MarathonRepository.ts | 4 +- packages/server/src/seed.ts | 95 ++++++++++++------- packages/server/src/types.d.ts | 6 -- 21 files changed, 185 insertions(+), 124 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 packages/server/prisma/migrations/20240710193233_job_state/migration.sql create mode 100644 packages/server/src/repositories/JobState.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3e387825..2240dbbd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/devcontainers/javascript-node:18 +FROM mcr.microsoft.com/devcontainers/javascript-node:22 # [Optional] Uncomment this section to install additional OS packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # && apt-get -y install --no-install-recommends -RUN curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok +# RUN curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok # [Optional] Uncomment if you want to install an additional version of node using nvm # ARG EXTRA_NODE_VERSION=10 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 324bb95a..1a60d1dc 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -45,11 +45,6 @@ "containerEnv": { "HOME": "/home/node", - "DB_HOST": "localhost", - "DB_PORT": "5432", - "DB_NAME": "danceblue", - "DB_UNAME": "danceblue", - "DB_PWD": "danceblue", "DATABASE_URL": "postgres://danceblue:danceblue@localhost:5432/danceblue?schema=danceblue", "NODE_ENV": "development", "APPLICATION_HOST": "localhost", diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..8c77820b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,25 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "msjsdiag.vscode-react-native", + "Prisma.prisma", + "esbenp.prettier-vscode", + "christian-kohler.npm-intellisense", + "VisualStudioExptTeam.vscodeintellicode", + "VisualStudioExptTeam.intellicode-api-usage-examples", + "cmstead.js-codeformer", + "cmstead.jsrefactor", + "ecmel.vscode-html-css", + "GraphQL.vscode-graphql-syntax", + "GraphQL.vscode-graphql", + "eamodio.gitlens", + "github.vscode-github-actions", + "expo.vscode-expo-tools", + "ms-azuretools.vscode-docker", + "naumovs.color-highlight", + "streetsidesoftware.code-spell-checker", + "vitest.explorer", + "GitHub.copilot", + "GitHub.vscode-pull-request-github" + ] +} \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index cd699826..cb8314d5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -3,24 +3,23 @@ services: postgres: container_name: danceblue-app-database-${SUBDOMAIN:?error} - image: postgres:latest + image: postgres:16 environment: POSTGRES_USER: danceblue POSTGRES_PASSWORD: danceblue POSTGRES_DB: danceblue - networks: - - database attach: false volumes: - - ./compose-volumes/postgres:/var/lib/postgresql/data + - danceblue-app-server-${SUBDOMAIN:?error}-database:/var/lib/postgresql/data server: container_name: danceblue-app-server-${SUBDOMAIN:?error} build: context: . dockerfile: ./packages/server/Dockerfile networks: - - database - proxy + links: + - postgres depends_on: - postgres env_file: ./packages/server/.env @@ -32,14 +31,10 @@ services: UPLOAD_PATH: /data/local-uploads MAX_FILE_SIZE: 200 LOG_DIR: /data/logs - DB_HOST: postgres - DB_NAME: danceblue - DB_UNAME: danceblue - DB_PWD: danceblue APPLICATION_HOST: danceblue-app-server-${SUBDOMAIN:?error} DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue volumes: - - danceblue-app-server-${SUBDOMAIN:?error}-data:/data:rw + - danceblue-app-server-${SUBDOMAIN:?error}-content:/data/local-uploads portal: container_name: danceblue-app-portal-${SUBDOMAIN:?error} networks: @@ -50,6 +45,13 @@ services: networks: database: + internal: true proxy: external: true name: proxy + +volumes: + "danceblue-app-server-${SUBDOMAIN:?error}-content": + driver: local + "danceblue-app-server-${SUBDOMAIN:?error}-database": + driver: local diff --git a/package.json b/package.json index 2b2c262c..4301bfc6 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "server:bs": "yarn workspace @ukdanceblue/server run bs", "server:build": "yarn workspace @ukdanceblue/server run build", "server:start": "yarn workspace @ukdanceblue/server run start", + "server:dev": "yarn workspace @ukdanceblue/server run dev", "server:prisma": "yarn workspace @ukdanceblue/server prisma", "server:prisma-generate": "yarn workspace @ukdanceblue/server prisma generate", "portal:dev": "yarn workspace @ukdanceblue/portal dev", diff --git a/packages/portal/Dockerfile b/packages/portal/Dockerfile index 40a98b3d..e59f2894 100644 --- a/packages/portal/Dockerfile +++ b/packages/portal/Dockerfile @@ -1,7 +1,3 @@ -FROM steebchen/nginx-spa:stable +FROM nginx:stable-alpine -COPY dist/ /app - -EXPOSE 80 - -CMD ["nginx"] +COPY dist/ /usr/share/nginx/html diff --git a/packages/server/.env.example b/packages/server/.env.example index a287a58a..5ab75912 100644 --- a/packages/server/.env.example +++ b/packages/server/.env.example @@ -1,9 +1,4 @@ # If using the dev container these values are set automatically: -DB_HOST=localhost -DB_PORT=5432 -DB_NAME=danceblue -DB_UNAME=danceblue -DB_PWD=danceblue DATABASE_URL=postgres://danceblue:danceblue@localhost:5432/danceblue?schema=danceblue NODE_ENV=development APPLICATION_HOST=localhost diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index f3c2a059..05bc0423 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -1,6 +1,6 @@ # Needs to be run with the context set to project root, i.e. docker build -t app-server ../.. -f Dockerfile -FROM node:18 +FROM node:22 ENV NODE_ENV="production" ENV APPLICATION_PORT="8000" @@ -11,12 +11,6 @@ EXPOSE ${APPLICATION_PORT} # ENV COOKIE_SECRET="" # ENV JWT_SECRET="" -ENV DB_HOST="app-database" -ENV DB_PORT="5432" -ENV DB_NAME="danceblue" -ENV DB_UNAME="danceblue" -# ENV DB_PWD="" - ENV MS_OIDC_URL="https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration" # ENV MS_CLIENT_ID="" # ENV MS_CLIENT_SECRET="" diff --git a/packages/server/package.json b/packages/server/package.json index 5eab3a4c..724b1589 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -5,15 +5,14 @@ "main": "dist/index.js", "type": "module", "engines": { - "node": ">=16.0.0" + "node": ">=22.0.0" }, "scripts": { "start": "node .", "build": "tsc", "bs": "yarn run build && yarn run start", - "this-is-bullshit": "yarn run bs", + "dev": "tsc --watch & node --watch . --watch-path=./dist", "migrate-and-start": "yarn dlx prisma migrate deploy && yarn run start", - "dev": "nodemon -w ./dist ./dist/index.js ../common/dist --", "test": "jest", "start-seed": "node . --seed-db --reset-db", "start-reset": "node . --reset-db", diff --git a/packages/server/prisma/migrations/20240710193233_job_state/migration.sql b/packages/server/prisma/migrations/20240710193233_job_state/migration.sql new file mode 100644 index 00000000..908e3cac --- /dev/null +++ b/packages/server/prisma/migrations/20240710193233_job_state/migration.sql @@ -0,0 +1,7 @@ +-- CreateTable +CREATE TABLE "job_states" ( + "job_name" TEXT NOT NULL, + "last_run" TIMESTAMPTZ(6) NOT NULL, + + CONSTRAINT "job_states_pkey" PRIMARY KEY ("job_name") +); diff --git a/packages/server/prisma/schema.prisma b/packages/server/prisma/schema.prisma index 4dc09283..3147a5c9 100644 --- a/packages/server/prisma/schema.prisma +++ b/packages/server/prisma/schema.prisma @@ -482,6 +482,13 @@ model FundraisingAssignment { @@map("fundraising_assignments") } +model JobState { + jobName String @id @map("job_name") + lastRun DateTime @map("last_run") @db.Timestamptz(6) + + @@map("job_states") +} + // Potential errors after sending a notification to Expo (see https://docs.expo.dev/push-notifications/sending-notifications/#individual-errors) enum NotificationError { // The device cannot receive push notifications anymore and you should stop sending messages to the corresponding Expo push token. diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index 42b4e88d..2e61259b 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -11,8 +11,6 @@ dotenv.config(); // Core env export const isDevelopment = process.env.NODE_ENV === "development"; -export const isProduction = process.env.NODE_ENV === "production"; -export const nodeEnvironment = process.env.NODE_ENV || "development"; export const loggingLevel: SyslogLevels = (process.env.LOGGING_LEVEL as SyslogLevels | undefined) ?? @@ -34,10 +32,9 @@ if (process.env.APPLICATION_PORT) { } export { applicationPort }; export const applicationHost = process.env.APPLICATION_HOST || "localhost"; -export const applicationProtocol = process.env.APPLICATION_PROTOCOL || "http"; // Secrets -const { COOKIE_SECRET, JWT_SECRET, ASSET_PATH } = process.env; +const { COOKIE_SECRET, JWT_SECRET } = process.env; if (!JWT_SECRET) { throw new Error("JWT_SECRET is not set"); } @@ -47,36 +44,6 @@ if (!COOKIE_SECRET) { export const cookieSecret = COOKIE_SECRET; export const jwtSecret = JWT_SECRET; -// System Paths -export const assetPath = ASSET_PATH; - -// Database -const { DB_HOST, DB_PORT, DB_UNAME, DB_PWD, DB_NAME } = process.env; -if (!DB_HOST) { - throw new Error("DB_HOST is not set"); -} -if (!DB_PORT) { - throw new Error("DB_PORT is not set"); -} -if (!DB_UNAME) { - throw new Error("DB_UNAME is not set"); -} -if (!DB_PWD) { - throw new Error("DB_PWD is not set"); -} -if (!DB_NAME) { - throw new Error("DB_NAME is not set"); -} -export const databaseHost = DB_HOST; -export const databasePort = DB_PORT; -export const databaseUsername = DB_UNAME; -export const databasePassword = DB_PWD; -export const databaseName = DB_NAME; - -// This check is used to try and prevent any chance of resetting the production database -// Obviously not foolproof, but it's better than nothing -export const isDatabaseLocal = databaseHost === "localhost" && isDevelopment; - // MS Auth const { MS_OIDC_URL, MS_CLIENT_ID, MS_CLIENT_SECRET } = process.env; if (!MS_OIDC_URL) { diff --git a/packages/server/src/jobs/fetchPushReceipts.ts b/packages/server/src/jobs/fetchPushReceipts.ts index 53ee64b8..3cc9d727 100644 --- a/packages/server/src/jobs/fetchPushReceipts.ts +++ b/packages/server/src/jobs/fetchPushReceipts.ts @@ -3,11 +3,14 @@ import { Container } from "typedi"; import { logger } from "#logging/standardLogging.js"; import { ExpoPushReceiptHandler } from "#notification/ExpoPushReceiptHandler.js"; +import { JobStateRepository } from "#repositories/JobState.js"; +const jobStateRepository = Container.get(JobStateRepository); export const fetchPushReceipts = new Cron( "0 */8 * * * *", { name: "fetch-push-receipts", + paused: true, catch: (error) => { console.error("Failed to fetch push receipts", error); }, @@ -17,8 +20,14 @@ export const fetchPushReceipts = new Cron( logger.info("Fetching push receipts"); const expoPushReceiptHandler = Container.get(ExpoPushReceiptHandler); await expoPushReceiptHandler.handlePushReceipts(); + + await jobStateRepository.logCompletedJob(fetchPushReceipts); } catch (error) { console.error("Failed to fetch push receipts", { error }); } } ); + +fetchPushReceipts.options.startAt = + await jobStateRepository.getNextJobDate(fetchPushReceipts); +fetchPushReceipts.resume(); diff --git a/packages/server/src/jobs/garbageCollectLogins.ts b/packages/server/src/jobs/garbageCollectLogins.ts index e2d70486..08f37bae 100644 --- a/packages/server/src/jobs/garbageCollectLogins.ts +++ b/packages/server/src/jobs/garbageCollectLogins.ts @@ -2,12 +2,15 @@ import Cron from "croner"; import { Container } from "typedi"; import { logger } from "#logging/standardLogging.js"; +import { JobStateRepository } from "#repositories/JobState.js"; import { LoginFlowSessionRepository } from "#repositories/LoginFlowSession.js"; +const jobStateRepository = Container.get(JobStateRepository); export const garbageCollectLoginFlowSessions = new Cron( "0 0 */6 * * *", { name: "garbage-collect-login-flow-sessions", + paused: true, catch: (error) => { console.error("Failed to fetch push receipts", error); }, @@ -19,8 +22,14 @@ export const garbageCollectLoginFlowSessions = new Cron( LoginFlowSessionRepository ); await loginFlowSessionRepository.gcOldLoginFlows(); + + await jobStateRepository.logCompletedJob(garbageCollectLoginFlowSessions); } catch (error) { console.error("Failed to garbage collect old login flows", { error }); } } ); + +garbageCollectLoginFlowSessions.options.startAt = + await jobStateRepository.getNextJobDate(garbageCollectLoginFlowSessions); +garbageCollectLoginFlowSessions.resume(); diff --git a/packages/server/src/jobs/index.ts b/packages/server/src/jobs/index.ts index 91751492..c0e14d80 100644 --- a/packages/server/src/jobs/index.ts +++ b/packages/server/src/jobs/index.ts @@ -1,12 +1,9 @@ import { Container } from "typedi"; import { NotificationScheduler } from "./NotificationScheduler.js"; -import { fetchPushReceipts } from "./fetchPushReceipts.js"; -import { garbageCollectLoginFlowSessions } from "./garbageCollectLogins.js"; -import { syncDbFunds } from "./syncDbFunds.js"; +import "./fetchPushReceipts.js"; +import "./garbageCollectLogins.js"; +import "./syncDbFunds.js"; -await fetchPushReceipts.trigger(); -await garbageCollectLoginFlowSessions.trigger(); -await syncDbFunds.trigger(); const scheduler = Container.get(NotificationScheduler); scheduler.ensureNotificationScheduler(); diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index 43b71090..ee8133c9 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -4,6 +4,7 @@ import { CompositeError, toBasicError } from "@ukdanceblue/common/error"; import Cron from "croner"; import { Err, None, Ok, type Result } from "ts-results-es"; import { Container } from "typedi"; +const jobStateRepository = Container.get(JobStateRepository); import type { PrismaError } from "#error/prisma.js"; import { @@ -11,6 +12,7 @@ import { type DBFundsFundraisingProviderError, } from "#lib/fundraising/DbFundsProvider.js"; import { logger } from "#logging/standardLogging.js"; +import { JobStateRepository } from "#repositories/JobState.js"; import { DBFundsRepository } from "#repositories/fundraising/DBFundsRepository.js"; import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; @@ -79,6 +81,7 @@ export const syncDbFunds = new Cron( "0 */11 * * * *", { name: "sync-db-funds", + paused: true, catch: (error) => { console.error("Failed to sync DBFunds", error); }, @@ -86,10 +89,16 @@ export const syncDbFunds = new Cron( async () => { logger.info("Syncing DBFunds"); const result = await doSync(); + if (result.isErr()) { logger.error("Failed to sync DBFunds", result.error); } else { logger.info("DBFunds sync complete"); + await jobStateRepository.logCompletedJob(syncDbFunds); } } ); + +syncDbFunds.options.startAt = + await jobStateRepository.getNextJobDate(syncDbFunds); +syncDbFunds.resume(); diff --git a/packages/server/src/lib/files/FileManager.ts b/packages/server/src/lib/files/FileManager.ts index 18ff9c99..00d1e4fa 100644 --- a/packages/server/src/lib/files/FileManager.ts +++ b/packages/server/src/lib/files/FileManager.ts @@ -17,8 +17,6 @@ const FILE_API = new URL("/api/file/download/", serveOrigin); logger.info(`Serving files from ${FILE_API.href}`); -logger.info(`Serving files from ${FILE_API.href}`); - @Service() export class FileManager { constructor( diff --git a/packages/server/src/repositories/JobState.ts b/packages/server/src/repositories/JobState.ts new file mode 100644 index 00000000..e4082d91 --- /dev/null +++ b/packages/server/src/repositories/JobState.ts @@ -0,0 +1,34 @@ +import { PrismaClient } from "@prisma/client"; +import Cron from "croner"; +import { Service } from "typedi"; + +@Service() +export class JobStateRepository { + constructor(private readonly prisma: PrismaClient) {} + + async logCompletedJob(job: Cron) { + const jobName = job.name; + const previousRun = job.previousRun(); + if (jobName && previousRun) { + await this.prisma.jobState.upsert({ + where: { jobName }, + update: { lastRun: previousRun }, + create: { jobName, lastRun: previousRun }, + }); + } + } + + async getNextJobDate(job: Cron) { + const jobName = job.name; + let baseDate = new Date(); + if (jobName) { + const jobState = await this.prisma.jobState.findUnique({ + where: { jobName }, + }); + if (jobState) { + baseDate = jobState.lastRun; + } + } + return job.nextRun(baseDate) ?? undefined; + } +} diff --git a/packages/server/src/repositories/marathon/MarathonRepository.ts b/packages/server/src/repositories/marathon/MarathonRepository.ts index 581bf3b8..c15b08e0 100644 --- a/packages/server/src/repositories/marathon/MarathonRepository.ts +++ b/packages/server/src/repositories/marathon/MarathonRepository.ts @@ -161,8 +161,8 @@ export class MarathonRepository { endDate, }: { year: string; - startDate: string; - endDate: string; + startDate?: string; + endDate?: string; }): Promise> { try { const marathon = await this.prisma.marathon.create({ diff --git a/packages/server/src/seed.ts b/packages/server/src/seed.ts index d6beaa62..14e24c5c 100644 --- a/packages/server/src/seed.ts +++ b/packages/server/src/seed.ts @@ -1,10 +1,17 @@ -import { CommitteeIdentifier, CommitteeRole } from "@ukdanceblue/common"; +import { + CommitteeIdentifier, + CommitteeRole, + TeamLegacyStatus, + TeamType, +} from "@ukdanceblue/common"; import { Container } from "typedi"; import { isDevelopment } from "#environment"; import { CommitteeRepository } from "#repositories/committee/CommitteeRepository.js"; import { ConfigurationRepository } from "#repositories/configuration/ConfigurationRepository.js"; +import { MarathonRepository } from "#repositories/marathon/MarathonRepository.js"; import { PersonRepository } from "#repositories/person/PersonRepository.js"; +import { TeamRepository } from "#repositories/team/TeamRepository.js"; if (!isDevelopment) { throw new Error("Seeding is only allowed in development mode"); @@ -15,6 +22,9 @@ const { prisma } = await import("./prisma.js"); try { const personRepository = Container.get(PersonRepository); const committeeRepository = Container.get(CommitteeRepository); + const teamRepository = Container.get(TeamRepository); + const configurationRepository = Container.get(ConfigurationRepository); + const marathonRepository = Container.get(MarathonRepository); const techCommittee: [string, string][] = [ ["jtho264@uky.edu", "jtho264"], @@ -41,18 +51,6 @@ try { throw new Error("Failed to create all tech committee people"); } - await Promise.all( - techPeople.flatMap((person) => - committeeRepository.assignPersonToCommittee( - { - id: person.unwrap().id, - }, - CommitteeIdentifier.techCommittee, - CommitteeRole.Coordinator - ) - ) - ); - const randomPeople = await Promise.all( randoms.map(([email, linkblue, name]) => personRepository.createPerson({ @@ -70,30 +68,55 @@ try { throw new Error("Failed to create all tech committee people"); } - // const teamRepository = Container.get(TeamRepository); - - // await teamRepository.createTeam({ - // name: "Tech Committee", - // legacyStatus: TeamLegacyStatus.ReturningTeam, - // marathonYear: "DB24", - // type: TeamType.Committee, - // memberships: { - // connect: techPeople, - // }, - // persistentIdentifier: CommitteeIdentifier.techCommittee, - // }); - - // await teamRepository.createTeam({ - // name: "Random People", - // legacyStatus: TeamLegacyStatus.NewTeam, - // marathonYear: "DB24", - // type: TeamType.Spirit, - // memberships: { - // connect: randomPeople, - // }, - // }); + const marathon = await marathonRepository.createMarathon({ + year: "DB24", + }); + + if (marathon.isErr()) { + throw new Error("Failed to create marathon"); + } - const configurationRepository = Container.get(ConfigurationRepository); + const techCommitteeTeam = await teamRepository.createTeam( + { + name: "Tech Committee", + legacyStatus: TeamLegacyStatus.ReturningTeam, + type: TeamType.Spirit, + }, + { id: marathon.value.id } + ); + + await teamRepository.createTeam( + { + name: "Random People", + legacyStatus: TeamLegacyStatus.NewTeam, + type: TeamType.Spirit, + }, + { id: marathon.value.id } + ); + + await teamRepository.updateTeam( + { id: techCommitteeTeam.id }, + { + correspondingCommittee: { + connect: { + identifier: CommitteeIdentifier.techCommittee, + }, + }, + } + ); + + await Promise.all( + techPeople.flatMap((person) => + committeeRepository.assignPersonToCommittee( + { + id: person.unwrap().id, + }, + CommitteeIdentifier.techCommittee, + CommitteeRole.Coordinator, + { id: marathon.value.id } + ) + ) + ); await configurationRepository.createConfiguration({ key: "TAB_BAR_CONFIG", diff --git a/packages/server/src/types.d.ts b/packages/server/src/types.d.ts index e7d1b3b3..68d10255 100644 --- a/packages/server/src/types.d.ts +++ b/packages/server/src/types.d.ts @@ -12,12 +12,6 @@ declare global { COOKIE_SECRET?: string; JWT_SECRET?: string; - DB_HOST?: string; - DB_PORT?: string; - DB_UNAME?: string; - DB_PWD?: string; - DB_NAME?: string; - // These don't need to be optional because they are checked in index.ts MS_OIDC_URL?: string; MS_CLIENT_ID?: string; From 855f2f654855445a661dc4dbf7f59e398d60e6c4 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 10 Jul 2024 20:50:00 +0000 Subject: [PATCH 146/153] Tweak job schedule logic --- packages/server/src/jobs/syncDbFunds.ts | 2 +- packages/server/src/lib/fundraising/DbFundsProvider.ts | 2 +- packages/server/src/repositories/JobState.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/jobs/syncDbFunds.ts b/packages/server/src/jobs/syncDbFunds.ts index ee8133c9..a9b14a14 100644 --- a/packages/server/src/jobs/syncDbFunds.ts +++ b/packages/server/src/jobs/syncDbFunds.ts @@ -78,7 +78,7 @@ async function doSync(): Promise< } export const syncDbFunds = new Cron( - "0 */11 * * * *", + "0 */31 * * * *", { name: "sync-db-funds", paused: true, diff --git a/packages/server/src/lib/fundraising/DbFundsProvider.ts b/packages/server/src/lib/fundraising/DbFundsProvider.ts index 368133ed..d0949ff6 100644 --- a/packages/server/src/lib/fundraising/DbFundsProvider.ts +++ b/packages/server/src/lib/fundraising/DbFundsProvider.ts @@ -118,7 +118,7 @@ export class DBFundsFundraisingProvider implements FundraisingProvider { const abort = new AbortController(); timeout = setTimeout(() => { abort.abort(); - }, 2500); + }, 5000); response = await fetch(url, { headers: { "X-AuthToken": this.dbFundsApiKey, diff --git a/packages/server/src/repositories/JobState.ts b/packages/server/src/repositories/JobState.ts index e4082d91..a16032c7 100644 --- a/packages/server/src/repositories/JobState.ts +++ b/packages/server/src/repositories/JobState.ts @@ -8,7 +8,7 @@ export class JobStateRepository { async logCompletedJob(job: Cron) { const jobName = job.name; - const previousRun = job.previousRun(); + const previousRun = job.currentRun(); if (jobName && previousRun) { await this.prisma.jobState.upsert({ where: { jobName }, From 6a302c511589d81cb71dbc9874b08d806a248b86 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 10 Jul 2024 21:24:16 +0000 Subject: [PATCH 147/153] Dockerfile updates --- packages/build.Dockerfile | 20 ++++++++++++++++++++ packages/portal/Dockerfile | 12 +++++++++++- packages/server/Dockerfile | 23 +++++++++++++++++------ 3 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 packages/build.Dockerfile diff --git a/packages/build.Dockerfile b/packages/build.Dockerfile new file mode 100644 index 00000000..cca776fd --- /dev/null +++ b/packages/build.Dockerfile @@ -0,0 +1,20 @@ +# Dockerfile to clone and prepare to build the project +FROM node:22 + +ARG REPO_URL + +RUN mkdir -p /builddir +WORKDIR /builddir + +RUN git clone ${REPO_URL} . + +RUN corepack enable + +RUN yarn workspaces focus @ukdanceblue/common + +RUN yarn run gql:build + +WORKDIR /builddir/packages/common + +RUN yarn build + diff --git a/packages/portal/Dockerfile b/packages/portal/Dockerfile index e59f2894..5b887af3 100644 --- a/packages/portal/Dockerfile +++ b/packages/portal/Dockerfile @@ -1,3 +1,13 @@ +FROM ../build.Dockerfile as build + +ENV VITE_API_BASE_URL="" + +WORKDIR /builddir/packages/portal + +RUN yarn workspaces focus @ukdanceblue/portal + +RUN yarn build + FROM nginx:stable-alpine -COPY dist/ /usr/share/nginx/html +COPY --from=build /builddir/packages/portal/dist /usr/share/nginx/html diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index 05bc0423..03ffc23b 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -1,4 +1,12 @@ -# Needs to be run with the context set to project root, i.e. docker build -t app-server ../.. -f Dockerfile +FROM ../build.Dockerfile as build + +WORKDIR /builddir/packages/server + +RUN yarn workspaces focus @ukdanceblue/server + +RUN yarn build + +RUN yarn workspaces focus @ukdanceblue/server --production FROM node:22 @@ -19,11 +27,14 @@ RUN mkdir -p /app/packages/server RUN mkdir -p /app/packages/common RUN mkdir -p /app/node_modules -COPY yarn.lock /app/yarn.lock -COPY package.json /app/package.json -COPY node_modules /app/node_modules/ -COPY packages/server /app/packages/server/ -COPY packages/common /app/packages/common/ +COPY --from=build /builddir/packages/server/dist /app/packages/server/dist +COPY --from=build /builddir/packages/server/package.json /app/packages/server/package.json +COPY --from=build /builddir/packages/server/yarn.lock /app/packages/server/yarn.lock +COPY --from=build /builddir/packages/server/node_modules /app/packages/server/node_modules +COPY --from=build /builddir/packages/common/dist /app/packages/common/dist +COPY --from=build /builddir/packages/common/package.json /app/packages/common/package.json +COPY --from=build /builddir/packages/common/yarn.lock /app/packages/common/yarn.lock +COPY --from=build /builddir/node_modules /app/node_modules WORKDIR /app/packages/server From 0ea03fca52c46e24b3173c0d4910e431ad18e7db Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Wed, 10 Jul 2024 21:37:10 +0000 Subject: [PATCH 148/153] More dockerfile stuff --- packages/{build.Dockerfile => Dockerfile} | 4 ++-- packages/portal/Dockerfile | 2 +- packages/server/Dockerfile | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename packages/{build.Dockerfile => Dockerfile} (80%) diff --git a/packages/build.Dockerfile b/packages/Dockerfile similarity index 80% rename from packages/build.Dockerfile rename to packages/Dockerfile index cca776fd..b2f970b9 100644 --- a/packages/build.Dockerfile +++ b/packages/Dockerfile @@ -1,12 +1,12 @@ # Dockerfile to clone and prepare to build the project FROM node:22 -ARG REPO_URL +ARG BRANCH RUN mkdir -p /builddir WORKDIR /builddir -RUN git clone ${REPO_URL} . +RUN git clone --single-branch --branch ${BRANCH} . RUN corepack enable diff --git a/packages/portal/Dockerfile b/packages/portal/Dockerfile index 5b887af3..3b6199be 100644 --- a/packages/portal/Dockerfile +++ b/packages/portal/Dockerfile @@ -1,4 +1,4 @@ -FROM ../build.Dockerfile as build +FROM build as build ENV VITE_API_BASE_URL="" diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index 03ffc23b..cc3c0da9 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -1,4 +1,4 @@ -FROM ../build.Dockerfile as build +FROM build as build WORKDIR /builddir/packages/server From 2c08a09c6946bb6a44bc49bdc053d653b8058ac2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 14 Jul 2024 19:31:25 +0000 Subject: [PATCH 149/153] Update devcontainer.json and compose.yaml --- .devcontainer/devcontainer.json | 1 + compose.yaml | 24 ++++++++++++++---------- packages/Dockerfile | 4 ++-- packages/portal/Dockerfile | 18 +++++++++++++++--- packages/server/Dockerfile | 18 +++++++++++++++--- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1a60d1dc..41ff9fbd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -50,6 +50,7 @@ "APPLICATION_HOST": "localhost", "APPLICATION_PORT": "8000", "MS_OIDC_URL": "https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration", + "SERVE_ORIGIN": "http://localhost:8000", "SERVE_PATH": "/workspaces/monorepo/local-uploads", "UPLOAD_PATH": "/workspaces/monorepo/local-uploads", "MAX_FILE_SIZE": "200", diff --git a/compose.yaml b/compose.yaml index cb8314d5..15650139 100644 --- a/compose.yaml +++ b/compose.yaml @@ -2,7 +2,7 @@ services: postgres: - container_name: danceblue-app-database-${SUBDOMAIN:?error} + container_name: danceblue-database-${SUBDOMAIN:?error} image: postgres:16 environment: POSTGRES_USER: danceblue @@ -10,9 +10,9 @@ services: POSTGRES_DB: danceblue attach: false volumes: - - danceblue-app-server-${SUBDOMAIN:?error}-database:/var/lib/postgresql/data + - database:/var/lib/postgresql/data server: - container_name: danceblue-app-server-${SUBDOMAIN:?error} + container_name: danceblue-server-${SUBDOMAIN:?error} build: context: . dockerfile: ./packages/server/Dockerfile @@ -31,16 +31,18 @@ services: UPLOAD_PATH: /data/local-uploads MAX_FILE_SIZE: 200 LOG_DIR: /data/logs - APPLICATION_HOST: danceblue-app-server-${SUBDOMAIN:?error} - DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue + LOGGING_LEVEL: debug + APPLICATION_HOST: "0.0.0.0" + DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue, + SERVE_ORIGIN: http://localhost:8000 volumes: - - danceblue-app-server-${SUBDOMAIN:?error}-content:/data/local-uploads + - content:/data/local-uploads portal: - container_name: danceblue-app-portal-${SUBDOMAIN:?error} + container_name: danceblue-portal-${SUBDOMAIN:?error} networks: - proxy build: - context: ./packages/portal + context: . dockerfile: ./packages/portal/Dockerfile networks: @@ -51,7 +53,9 @@ networks: name: proxy volumes: - "danceblue-app-server-${SUBDOMAIN:?error}-content": + content: driver: local - "danceblue-app-server-${SUBDOMAIN:?error}-database": + name: danceblue-server-${SUBDOMAIN:?error}-content + database: driver: local + name: danceblue-server-${SUBDOMAIN:?error}-database diff --git a/packages/Dockerfile b/packages/Dockerfile index b2f970b9..88e1c6fa 100644 --- a/packages/Dockerfile +++ b/packages/Dockerfile @@ -4,9 +4,9 @@ FROM node:22 ARG BRANCH RUN mkdir -p /builddir -WORKDIR /builddir -RUN git clone --single-branch --branch ${BRANCH} . +COPY .. /builddir/ +WORKDIR /builddir RUN corepack enable diff --git a/packages/portal/Dockerfile b/packages/portal/Dockerfile index 3b6199be..fc4a8bc5 100644 --- a/packages/portal/Dockerfile +++ b/packages/portal/Dockerfile @@ -1,10 +1,22 @@ -FROM build as build +FROM node:22 as build -ENV VITE_API_BASE_URL="" +RUN corepack enable + +RUN mkdir -p /builddir +ADD . /builddir/ +WORKDIR /builddir + +RUN yarn install --immutable + +RUN yarn run gql:build + +WORKDIR /builddir/packages/common + +RUN yarn build WORKDIR /builddir/packages/portal -RUN yarn workspaces focus @ukdanceblue/portal +ENV VITE_API_BASE_URL="" RUN yarn build diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile index cc3c0da9..0e4e71f6 100644 --- a/packages/server/Dockerfile +++ b/packages/server/Dockerfile @@ -1,8 +1,20 @@ -FROM build as build +FROM node:22 as build -WORKDIR /builddir/packages/server +RUN corepack enable + +RUN mkdir -p /builddir +ADD . /builddir +WORKDIR /builddir + +RUN yarn install --immutable + +RUN yarn run gql:build -RUN yarn workspaces focus @ukdanceblue/server +WORKDIR /builddir/packages/common + +RUN yarn build + +WORKDIR /builddir/packages/server RUN yarn build From bd96bedc6eec493f72e496329bbc5705454ab8ae Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Sun, 14 Jul 2024 20:20:30 +0000 Subject: [PATCH 150/153] Merge dockerfiles --- Dockerfile | 74 ++++++++++++++++++++++++++++++++++++++ codegen.ts | 47 +++++++++++++----------- compose.yaml | 18 +++++----- packages/Dockerfile | 20 ----------- packages/portal/Dockerfile | 25 ------------- packages/server/Dockerfile | 53 --------------------------- 6 files changed, 110 insertions(+), 127 deletions(-) create mode 100644 Dockerfile delete mode 100644 packages/Dockerfile delete mode 100644 packages/portal/Dockerfile delete mode 100644 packages/server/Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..7a07c5cc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,74 @@ +# syntax=docker/dockerfile:1.7-labs +FROM node:22 as build + +RUN mkdir -p /builddir +ADD --exclude=packages/mobile . /builddir +WORKDIR /builddir + +RUN corepack yarn install + +RUN corepack yarn run gql:build + +WORKDIR /builddir/packages/common + +RUN corepack yarn build + +# Server build +FROM build as server-build + +WORKDIR /builddir/packages/server + +RUN corepack yarn prisma generate + +RUN corepack yarn build + +RUN corepack yarn workspaces focus --production -A + +# Portal build +FROM build as portal-build + +WORKDIR /builddir/packages/portal + +ENV VITE_API_BASE_URL="" + +RUN corepack yarn build + +# Server +FROM node:22 as server + +ENV NODE_ENV="production" +ENV APPLICATION_PORT="8000" +ENV APPLICATION_HOST="0.0.0.0" + +EXPOSE ${APPLICATION_PORT} + +# ENV COOKIE_SECRET="" +# ENV JWT_SECRET="" + +ENV MS_OIDC_URL="https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration" +# ENV MS_CLIENT_ID="" +# ENV MS_CLIENT_SECRET="" + +RUN mkdir -p /app/packages/server +RUN mkdir -p /app/packages/common +RUN mkdir -p /app/.yarn +RUN mkdir -p /app/node_modules + +COPY --from=server-build /builddir/packages/server/dist /app/packages/server/dist +COPY --from=server-build /builddir/packages/server/node_modules /app/packages/server/node_modules +COPY --from=server-build /builddir/packages/server/prisma /app/packages/server/prisma +COPY --from=server-build /builddir/packages/server/package.json /app/packages/server/package.json +COPY --from=server-build /builddir/packages/common/dist /app/packages/common/dist +COPY --from=server-build /builddir/packages/common/package.json /app/packages/common/package.json +COPY --from=server-build /builddir/node_modules /app/node_modules +COPY --from=server-build /builddir/package.json /app/package.json +COPY --from=server-build /builddir/yarn.lock /app/yarn.lock + +WORKDIR /app/packages/server + +CMD corepack yarn dlx prisma migrate deploy && node . + +# Portal +FROM nginx:stable-alpine as portal + +COPY --from=portal-build /builddir/packages/portal/dist /usr/share/nginx/html diff --git a/codegen.ts b/codegen.ts index 09e06cd1..dcafda45 100644 --- a/codegen.ts +++ b/codegen.ts @@ -1,3 +1,4 @@ +import { readdirSync } from "fs"; import type { CodegenConfig } from "@graphql-codegen/cli"; import type { ClientPresetConfig } from "@graphql-codegen/client-preset"; import type { TypeScriptPluginConfig } from "@graphql-codegen/typescript"; @@ -54,6 +55,31 @@ const config: TypeScriptPluginConfig = { }, strictScalars: true, }; + +const generates: CodegenConfig["generates"] = {}; +const packages = readdirSync("./packages"); +if (packages.includes("mobile")) { + generates["./packages/common/lib/graphql-client-public/"] = { + preset: "client", + presetConfig, + config, + documents: [ + "./packages/mobile/src/**/*.ts", + "./packages/mobile/src/**/*.tsx", + ], + }; +} +if (packages.includes("portal")) { + generates["./packages/common/lib/graphql-client-internal/"] = { + preset: "client", + presetConfig, + config, + documents: [ + "./packages/portal/src/**/*.ts", + "./packages/portal/src/**/*.tsx", + ], + }; +} const codegenConfig: CodegenConfig = { schema: "schema.graphql", hooks: { @@ -62,26 +88,7 @@ const codegenConfig: CodegenConfig = { }, }, emitLegacyCommonJSImports: false, - generates: { - "./packages/common/lib/graphql-client-public/": { - preset: "client", - presetConfig, - config, - documents: [ - "./packages/mobile/src/**/*.ts", - "./packages/mobile/src/**/*.tsx", - ], - }, - "./packages/common/lib/graphql-client-admin/": { - preset: "client", - presetConfig, - config, - documents: [ - "./packages/portal/src/**/*.ts", - "./packages/portal/src/**/*.tsx", - ], - }, - }, + generates, }; export default codegenConfig; diff --git a/compose.yaml b/compose.yaml index 15650139..4b207c8d 100644 --- a/compose.yaml +++ b/compose.yaml @@ -4,6 +4,8 @@ services: postgres: container_name: danceblue-database-${SUBDOMAIN:?error} image: postgres:16 + networks: + - database environment: POSTGRES_USER: danceblue POSTGRES_PASSWORD: danceblue @@ -13,37 +15,35 @@ services: - database:/var/lib/postgresql/data server: container_name: danceblue-server-${SUBDOMAIN:?error} + pull_policy: build build: context: . - dockerfile: ./packages/server/Dockerfile + target: server networks: - proxy - links: - - postgres + - database depends_on: - postgres - env_file: ./packages/server/.env + env_file: ${ENV_PATH:-./packages/server/.env} environment: NODE_ENV: ${NODE_ENV:-production} - APPLICATION_PORT: 8000 MS_OIDC_URL: https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration SERVE_PATH: /data/local-uploads UPLOAD_PATH: /data/local-uploads MAX_FILE_SIZE: 200 LOG_DIR: /data/logs - LOGGING_LEVEL: debug - APPLICATION_HOST: "0.0.0.0" - DATABASE_URL: postgres://danceblue:danceblue@postgres:5432/danceblue, + DATABASE_URL: postgres://danceblue:danceblue@danceblue-database-${SUBDOMAIN:?error}:5432/danceblue SERVE_ORIGIN: http://localhost:8000 volumes: - content:/data/local-uploads portal: container_name: danceblue-portal-${SUBDOMAIN:?error} + pull_policy: build networks: - proxy build: context: . - dockerfile: ./packages/portal/Dockerfile + target: portal networks: database: diff --git a/packages/Dockerfile b/packages/Dockerfile deleted file mode 100644 index 88e1c6fa..00000000 --- a/packages/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -# Dockerfile to clone and prepare to build the project -FROM node:22 - -ARG BRANCH - -RUN mkdir -p /builddir - -COPY .. /builddir/ -WORKDIR /builddir - -RUN corepack enable - -RUN yarn workspaces focus @ukdanceblue/common - -RUN yarn run gql:build - -WORKDIR /builddir/packages/common - -RUN yarn build - diff --git a/packages/portal/Dockerfile b/packages/portal/Dockerfile deleted file mode 100644 index fc4a8bc5..00000000 --- a/packages/portal/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM node:22 as build - -RUN corepack enable - -RUN mkdir -p /builddir -ADD . /builddir/ -WORKDIR /builddir - -RUN yarn install --immutable - -RUN yarn run gql:build - -WORKDIR /builddir/packages/common - -RUN yarn build - -WORKDIR /builddir/packages/portal - -ENV VITE_API_BASE_URL="" - -RUN yarn build - -FROM nginx:stable-alpine - -COPY --from=build /builddir/packages/portal/dist /usr/share/nginx/html diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile deleted file mode 100644 index 0e4e71f6..00000000 --- a/packages/server/Dockerfile +++ /dev/null @@ -1,53 +0,0 @@ -FROM node:22 as build - -RUN corepack enable - -RUN mkdir -p /builddir -ADD . /builddir -WORKDIR /builddir - -RUN yarn install --immutable - -RUN yarn run gql:build - -WORKDIR /builddir/packages/common - -RUN yarn build - -WORKDIR /builddir/packages/server - -RUN yarn build - -RUN yarn workspaces focus @ukdanceblue/server --production - -FROM node:22 - -ENV NODE_ENV="production" -ENV APPLICATION_PORT="8000" -ENV APPLICATION_HOST="0.0.0.0" - -EXPOSE ${APPLICATION_PORT} - -# ENV COOKIE_SECRET="" -# ENV JWT_SECRET="" - -ENV MS_OIDC_URL="https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration" -# ENV MS_CLIENT_ID="" -# ENV MS_CLIENT_SECRET="" - -RUN mkdir -p /app/packages/server -RUN mkdir -p /app/packages/common -RUN mkdir -p /app/node_modules - -COPY --from=build /builddir/packages/server/dist /app/packages/server/dist -COPY --from=build /builddir/packages/server/package.json /app/packages/server/package.json -COPY --from=build /builddir/packages/server/yarn.lock /app/packages/server/yarn.lock -COPY --from=build /builddir/packages/server/node_modules /app/packages/server/node_modules -COPY --from=build /builddir/packages/common/dist /app/packages/common/dist -COPY --from=build /builddir/packages/common/package.json /app/packages/common/package.json -COPY --from=build /builddir/packages/common/yarn.lock /app/packages/common/yarn.lock -COPY --from=build /builddir/node_modules /app/node_modules - -WORKDIR /app/packages/server - -CMD corepack yarn run migrate-and-start From 8d37043355f5ac972e9b014f0435a7aea9904d3c Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 19 Jul 2024 18:46:05 +0000 Subject: [PATCH 151/153] Update Dockerfile and compose.yaml configurations to use secrets --- Dockerfile | 18 +-- compose.yaml | 68 ++++++++++- packages/server/src/environment.ts | 175 +++++++++++++++-------------- 3 files changed, 161 insertions(+), 100 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7a07c5cc..c67a25e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ # syntax=docker/dockerfile:1.7-labs -FROM node:22 as build +FROM node:22.4.1 as build + +ADD --link --exclude=packages/mobile . /builddir -RUN mkdir -p /builddir -ADD --exclude=packages/mobile . /builddir WORKDIR /builddir RUN corepack yarn install @@ -34,21 +34,13 @@ ENV VITE_API_BASE_URL="" RUN corepack yarn build # Server -FROM node:22 as server +FROM node:22.4.1 as server +ENV MS_OIDC_URL="https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration" ENV NODE_ENV="production" ENV APPLICATION_PORT="8000" ENV APPLICATION_HOST="0.0.0.0" -EXPOSE ${APPLICATION_PORT} - -# ENV COOKIE_SECRET="" -# ENV JWT_SECRET="" - -ENV MS_OIDC_URL="https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration" -# ENV MS_CLIENT_ID="" -# ENV MS_CLIENT_SECRET="" - RUN mkdir -p /app/packages/server RUN mkdir -p /app/packages/common RUN mkdir -p /app/.yarn diff --git a/compose.yaml b/compose.yaml index 4b207c8d..848dc7ef 100644 --- a/compose.yaml +++ b/compose.yaml @@ -15,30 +15,47 @@ services: - database:/var/lib/postgresql/data server: container_name: danceblue-server-${SUBDOMAIN:?error} - pull_policy: build build: context: . target: server + image: ghcr.io/ukdanceblue/app-server:${VERSION:-latest} networks: - proxy - database depends_on: - postgres - env_file: ${ENV_PATH:-./packages/server/.env} environment: NODE_ENV: ${NODE_ENV:-production} - MS_OIDC_URL: https://login.microsoftonline.com/2b30530b-69b6-4457-b818-481cb53d42ae/v2.0/.well-known/openid-configuration SERVE_PATH: /data/local-uploads UPLOAD_PATH: /data/local-uploads MAX_FILE_SIZE: 200 LOG_DIR: /data/logs DATABASE_URL: postgres://danceblue:danceblue@danceblue-database-${SUBDOMAIN:?error}:5432/danceblue SERVE_ORIGIN: http://localhost:8000 + secrets: + - application_port + - application_host + - cookie_secret + - jwt_secret + - db_host + - db_port + - db_uname + - db_pwd + - db_name + - database_url + - ms_client_id + - ms_client_secret + - expo_access_token + - serve_origin + - logging_level + - dbfunds_api_origin + - dbfunds_api_key + - log_dir volumes: - content:/data/local-uploads portal: container_name: danceblue-portal-${SUBDOMAIN:?error} - pull_policy: build + image: ghcr.io/ukdanceblue/app-portal:${VERSION:-latest} networks: - proxy build: @@ -59,3 +76,46 @@ volumes: database: driver: local name: danceblue-server-${SUBDOMAIN:?error}-database + +# Secrets from environment variables (i.e. var: environment: VAR) +# secrets: +# token: +# environment: "OAUTH_TOKEN" + +secrets: + application_port: + environment: "APPLICATION_PORT" + application_host: + environment: "APPLICATION_HOST" + cookie_secret: + environment: "COOKIE_SECRET" + jwt_secret: + environment: "JWT_SECRET" + db_host: + environment: "DB_HOST" + db_port: + environment: "DB_PORT" + db_uname: + environment: "DB_UNAME" + db_pwd: + environment: "DB_PWD" + db_name: + environment: "DB_NAME" + database_url: + environment: "DATABASE_URL" + ms_client_id: + environment: "MS_CLIENT_ID" + ms_client_secret: + environment: "MS_CLIENT_SECRET" + expo_access_token: + environment: "EXPO_ACCESS_TOKEN" + serve_origin: + environment: "SERVE_ORIGIN" + logging_level: + environment: "LOGGING_LEVEL" + dbfunds_api_origin: + environment: "DBFUNDS_API_ORIGIN" + dbfunds_api_key: + environment: "DBFUNDS_API_KEY" + log_dir: + environment: "LOG_DIR" diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index 2e61259b..17ec833e 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -6,121 +6,135 @@ import { Expo } from "expo-server-sdk"; import { Container, Token } from "typedi"; import type { SyslogLevels } from "#logging/standardLogging.js"; +import { readFile } from "fs/promises"; dotenv.config(); -// Core env +async function getEnv( + name: string, + def?: undefined +): Promise; +async function getEnv(name: string, def: string | null): Promise; +async function getEnv( + name: string, + def?: string | null +): Promise { + let value; + if (process.env[`${name}_FILE`]) { + try { + value = await readFile(process.env[`${name}_FILE`]!, "utf-8"); + } catch { + value = process.env[name]; + } + } else { + const lowercaseName = name.toLowerCase(); + try { + value = await readFile(`/run/secrets/${lowercaseName}`, "utf-8"); + } catch { + value = process.env[name]; + } + } + + if (!value) { + if (def === null) { + throw new Error(`Env variable '${name}' is not set`); + } + if (def !== undefined) { + return def; + } + } + + return value; +} + export const isDevelopment = process.env.NODE_ENV === "development"; -export const loggingLevel: SyslogLevels = - (process.env.LOGGING_LEVEL as SyslogLevels | undefined) ?? - (isDevelopment ? "debug" : "notice"); +const LOGGING_LEVEL = getEnv( + "LOGGING_LEVEL", + isDevelopment ? "debug" : "notice" +); +const APPLICATION_PORT = getEnv("APPLICATION_PORT", "8000"); +const APPLICATION_HOST = getEnv("APPLICATION_HOST", "localhost"); +const COOKIE_SECRET = getEnv("COOKIE_SECRET", null); +const JWT_SECRET = getEnv("JWT_SECRET", null); +const MS_OIDC_URL = getEnv("MS_OIDC_URL", null); +const MS_CLIENT_ID = getEnv("MS_CLIENT_ID", null); +const MS_CLIENT_SECRET = getEnv("MS_CLIENT_SECRET", null); +const EXPO_ACCESS_TOKEN = getEnv("EXPO_ACCESS_TOKEN", null); +const DBFUNDS_API_KEY = getEnv("DBFUNDS_API_KEY", null); +const DBFUNDS_API_ORIGIN = getEnv("DBFUNDS_API_ORIGIN", null); +const MAX_FILE_SIZE = getEnv("MAX_FILE_SIZE", null); +const SERVE_PATH = getEnv("SERVE_PATH", null); +const UPLOAD_PATH = getEnv("UPLOAD_PATH", null); +const SERVE_ORIGIN = getEnv("SERVE_ORIGIN", null); +const OVERRIDE_AUTH = getEnv("OVERRIDE_AUTH", null); +const LOG_DIR = getEnv("LOG_DIR", null); + +// Core env +export const loggingLevel: SyslogLevels = (await LOGGING_LEVEL) as SyslogLevels; // Port, Host, and Protocol -let applicationPort: number = 8000; -if (process.env.APPLICATION_PORT) { - const envApplicationPort = Number.parseInt(process.env.APPLICATION_PORT, 10); - if (Number.isNaN(envApplicationPort)) { - throw new TypeError("Env variable 'APPLICATION_PORT' is not a number"); - } - if (envApplicationPort < 0 || envApplicationPort > 65_535) { - throw new RangeError( - "Env variable 'APPLICATION_PORT' is not a valid port number" - ); - } - applicationPort = envApplicationPort; +export const applicationPort = Number.parseInt(await APPLICATION_PORT, 10); +if (Number.isNaN(applicationPort)) { + throw new TypeError("Env variable 'APPLICATION_PORT' is not a number"); +} +if (applicationPort < 0 || applicationPort > 65_535) { + throw new RangeError( + "Env variable 'APPLICATION_PORT' is not a valid port number" + ); } -export { applicationPort }; -export const applicationHost = process.env.APPLICATION_HOST || "localhost"; + +export const applicationHost = await APPLICATION_HOST; // Secrets -const { COOKIE_SECRET, JWT_SECRET } = process.env; -if (!JWT_SECRET) { - throw new Error("JWT_SECRET is not set"); -} -if (!COOKIE_SECRET) { - throw new Error("COOKIE_SECRET is not set"); -} -export const cookieSecret = COOKIE_SECRET; -export const jwtSecret = JWT_SECRET; +export const cookieSecret = await COOKIE_SECRET; +export const jwtSecret = await JWT_SECRET; // MS Auth -const { MS_OIDC_URL, MS_CLIENT_ID, MS_CLIENT_SECRET } = process.env; -if (!MS_OIDC_URL) { - throw new Error("MS_OIDC_URL is not set"); -} -if (!MS_CLIENT_ID) { - throw new Error("MS_CLIENT_ID is not set"); -} -if (!MS_CLIENT_SECRET) { - throw new Error("MS_CLIENT_SECRET is not set"); -} -export const msOidcUrl = MS_OIDC_URL; -export const msClientId = MS_CLIENT_ID; -export const msClientSecret = MS_CLIENT_SECRET; +export const msOidcUrl = await MS_OIDC_URL; +export const msClientId = await MS_CLIENT_ID; +export const msClientSecret = await MS_CLIENT_SECRET; // Expo access token -const { EXPO_ACCESS_TOKEN } = process.env; -if (!EXPO_ACCESS_TOKEN) { - throw new Error("EXPO_ACCESS_TOKEN is not set"); -} -export const expoAccessToken = EXPO_ACCESS_TOKEN; +export const expoAccessToken = await EXPO_ACCESS_TOKEN; Container.set(Expo, new Expo({ accessToken: expoAccessToken })); // DBFunds -const { DBFUNDS_API_KEY, DBFUNDS_API_ORIGIN } = process.env; -if (!DBFUNDS_API_KEY) { - throw new Error("DBFUNDS_API_KEY is not set"); -} -if (!DBFUNDS_API_ORIGIN) { - throw new Error("DBFUNDS_API_ORIGIN is not set"); -} export const dbFundsApiKeyToken = new Token("DBFUNDS_API_KEY"); export const dbFundsApiOriginToken = new Token("DBFUNDS_API_ORIGIN"); -Container.set(dbFundsApiKeyToken, DBFUNDS_API_KEY); -Container.set(dbFundsApiOriginToken, DBFUNDS_API_ORIGIN); +Container.set(dbFundsApiKeyToken, await DBFUNDS_API_KEY); +Container.set(dbFundsApiOriginToken, await DBFUNDS_API_ORIGIN); // File upload settings -const { MAX_FILE_SIZE, SERVE_PATH, UPLOAD_PATH, SERVE_ORIGIN } = process.env; -if (!MAX_FILE_SIZE) { - throw new Error("MAX_FILE_SIZE is not set"); -} -if (!SERVE_PATH) { - throw new Error("SERVE_PATH is not set"); -} -if (!UPLOAD_PATH) { - throw new Error("UPLOAD_PATH is not set"); -} -if (!SERVE_ORIGIN) { - throw new Error("SERVE_ORIGIN is not set"); -} +export const serveOrigin = await SERVE_ORIGIN; try { - new URL(SERVE_ORIGIN); + new URL(serveOrigin); } catch { throw new Error("SERVE_ORIGIN is not a valid URL"); } +export const servePath = await SERVE_PATH; +export const uploadPath = await UPLOAD_PATH; -const maxFileSize = Number.parseInt(MAX_FILE_SIZE, 10); +export const maxFileSize = Number.parseInt(await MAX_FILE_SIZE, 10); if (Number.isNaN(maxFileSize)) { throw new TypeError("MAX_FILE_SIZE is not a number"); } if (maxFileSize < 10) { throw new RangeError("MAX_FILE_SIZE must be at least 10 (MB)"); } -export { maxFileSize }; -if (!isAbsolute(SERVE_PATH) || !isAbsolute(UPLOAD_PATH)) { +if (!isAbsolute(servePath) || !isAbsolute(uploadPath)) { throw new Error("SERVE_PATH and UPLOAD_PATH must be absolute paths"); } -if (statSync(SERVE_PATH).isFile() || statSync(UPLOAD_PATH).isFile()) { +if (statSync(servePath).isFile() || statSync(uploadPath).isFile()) { throw new Error("SERVE_PATH and UPLOAD_PATH must be directories"); } -let uploadParentPath = UPLOAD_PATH; +let uploadParentPath = uploadPath; let isUploadInServe = false; while (path.dirname(uploadParentPath) !== uploadParentPath) { - if (uploadParentPath === SERVE_PATH) { + if (uploadParentPath === servePath) { isUploadInServe = true; break; } @@ -130,17 +144,12 @@ if (!isUploadInServe) { throw new Error("UPLOAD_PATH must be a subdirectory of SERVE_PATH"); } -export const serveOrigin = SERVE_ORIGIN; -export const servePath = SERVE_PATH; -export const uploadPath = UPLOAD_PATH; - // Disable all authorization checks -const { OVERRIDE_AUTH } = process.env; -export const authorizationOverride = OVERRIDE_AUTH === "THIS IS DANGEROUS"; +export const authorizationOverride = + isDevelopment && (await OVERRIDE_AUTH) === "THIS IS DANGEROUS"; // Log directory -const { LOG_DIR } = process.env; -if (!LOG_DIR) { +export const logDir = await LOG_DIR; +if (!logDir) { throw new Error("LOG_DIR is not set"); } -export const logDir = LOG_DIR; From ba2c91eef4e4b679473e475e16e524d5fd346aca Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 19 Jul 2024 19:10:23 +0000 Subject: [PATCH 152/153] Update github action to build new dockerfile --- .github/workflows/docker-build.yml | 138 ++++++-------------------- .github/workflows/main-to-release.yml | 26 ----- 2 files changed, 33 insertions(+), 131 deletions(-) delete mode 100644 .github/workflows/main-to-release.yml diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 0a63aef1..2ae97194 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -19,7 +19,7 @@ env: SERVER_IMAGE_NAME: ukdanceblue/app-server jobs: - build-and-push-portal-image: + build-and-push-images: runs-on: ubuntu-latest permissions: contents: read @@ -27,126 +27,54 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Enable Corepack before setting up Node - run: corepack enable - - name: Set up node 18.x - uses: actions/setup-node@v4.0.2 - with: - node-version: 18 - cache: yarn - - name: Install dependencies - working-directory: ./packages/portal - run: - yarn workspaces focus @ukdanceblue/common @ukdanceblue/portal - @ukdanceblue/monorepo - - name: Build GraphQL - run: yarn run gql:build - working-directory: . - - name: Build common - run: yarn run build - working-directory: ./packages/common - - name: Build portal - run: yarn run build - working-directory: ./packages/portal # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 + id: portalMeta + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.PORTAL_IMAGE_NAME }} - # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. - # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. - # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build and push Docker image - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 - with: - context: ./packages/portal - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - build-and-push-server-image: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Enable Corepack before setting up Node - run: corepack enable - - name: Set up node 18.x - uses: actions/setup-node@v4.0.2 - with: - node-version: 18 - cache: yarn - - name: Install dependencies - working-directory: ./packages/server - run: - yarn workspaces focus @ukdanceblue/common @ukdanceblue/server - @ukdanceblue/monorepo - - name: Build common - run: yarn run build - working-directory: ./packages/common - - name: Generate prisma client - run: yarn dlx prisma generate - working-directory: ./packages/server - - name: Build server - run: yarn run build - working-directory: ./packages/server - - name: Focus on server - run: - yarn workspaces focus --production @ukdanceblue/server - @ukdanceblue/common - # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - - name: Log in to the Container registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 + id: serverMeta + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.SERVER_IMAGE_NAME }} # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - - name: Build and push Docker image - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 + - name: Build and push Portal image + uses: docker/build-push-action@v6 with: context: . - file: ./packages/server/Dockerfile push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - trigger-recreate-release: - runs-on: ubuntu-latest - needs: [build-and-push-portal-image, build-and-push-server-image] - if: github.ref == 'refs/heads/release' - steps: - - name: Trigger container recreate - shell: bash - run: | - ((curl --insecure -X POST ${{ secrets.DANCEBLUE_APP_PORTAL_RECREATE_WEBHOOK }} -H "CF-Access-Client-Id: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_ID }}" -H "CF-Access-Client-Secret: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_SECRET }}") || exit 1) - ((curl --insecure -X POST ${{ secrets.DANCEBLUE_APP_SERVER_RECREATE_WEBHOOK }} -H "CF-Access-Client-Id: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_ID }}" -H "CF-Access-Client-Secret: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_SECRET }}") || exit 1) - trigger-recreate-main: - runs-on: ubuntu-latest - needs: [build-and-push-portal-image, build-and-push-server-image] - if: github.ref == 'refs/heads/main' - steps: - - name: Trigger container recreate - shell: bash - run: | - ((curl --insecure -X POST ${{ secrets.DANCEBLUE_APP_DEV_PORTAL_RECREATE_WEBHOOK }} -H "CF-Access-Client-Id: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_ID }}" -H "CF-Access-Client-Secret: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_SECRET }}") || exit 1) - ((curl --insecure -X POST ${{ secrets.DANCEBLUE_APP_DEV_SERVER_RECREATE_WEBHOOK }} -H "CF-Access-Client-Id: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_ID }}" -H "CF-Access-Client-Secret: ${{ secrets.CLOUDFLARE_ACCESS_SERVICE_TOKEN_CLIENT_SECRET }}") || exit 1) + tags: ${{ steps.portalMeta.outputs.tags }} + labels: ${{ steps.portalMeta.outputs.labels }} + target: portal + - name: Build and push Server image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.serverMeta.outputs.tags }} + labels: ${{ steps.serverMeta.outputs.labels }} + target: server + - name: Remove old Portal images + uses: actions/delete-package-versions@v5 + with: + package-name: ${{ env.PORTAL_IMAGE_NAME }} + package-type: "container" + min-versions-to-keep: 2 + delete-only-untagged-versions: "true" + - name: Remove old Server images + uses: actions/delete-package-versions@v5 + with: + package-name: ${{ env.SERVER_IMAGE_NAME }} + package-type: "container" + min-versions-to-keep: 2 + delete-only-untagged-versions: "true" diff --git a/.github/workflows/main-to-release.yml b/.github/workflows/main-to-release.yml deleted file mode 100644 index 0acd1889..00000000 --- a/.github/workflows/main-to-release.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Open pull request to release branch - -on: - push: - branches: - - main - -jobs: - release: - runs-on: ubuntu-latest - steps: - # First, get all the open pull requests that target the release branch using the GitHub CLI - - name: Get open pull requests - id: get_prs - run: | - gh pr list --state open --base release --json number,title -R ukdanceblue/monorepo > prs.json - echo "prs=$(cat prs.json)" >> $GITHUB_OUTPUT - env: - GH_TOKEN: ${{ github.token }} - # If the array is empty, there are no open pull requests, so we can open one - - name: Open pull request - if: steps.get_prs.outputs.prs == '[]' - run: | - gh pr create --title "Update Release Branch" --body "This pull request was automatically opened by a GitHub Action." --base release --head main --draft -R ukdanceblue/monorepo - env: - GH_TOKEN: ${{ github.token }} From f037a88508f9ee8268dffc0275128496137602d2 Mon Sep 17 00:00:00 2001 From: Joshua Tag Howard Date: Fri, 19 Jul 2024 19:31:57 +0000 Subject: [PATCH 153/153] Rename graphql lib dirs --- codegen.ts | 4 ++-- .../fragment-masking.ts | 0 .../gql.ts | 0 .../graphql.ts | 0 .../index.ts | 0 .../fragment-masking.ts | 0 .../gql.ts | 0 .../graphql.ts | 0 .../index.ts | 0 packages/common/package.json | 23 ++++++++++--------- .../common/components/ImageView/ImageView.tsx | 4 ++-- .../src/common/fragments/Configuration.ts | 2 +- .../common/fragments/NotificationScreenGQL.ts | 2 +- .../src/common/hooks/useAllowedLoginTypes.ts | 2 +- .../src/common/hooks/useMarathonTime.ts | 2 +- .../src/common/hooks/useTabBarConfig.ts | 2 +- .../common/marathonComponents/TriviaCrack.tsx | 2 +- packages/mobile/src/context/auth.tsx | 2 +- packages/mobile/src/context/device.tsx | 2 +- .../root/EventScreen/EventScreen.tsx | 2 +- .../root/EventScreen/EventScreenFragment.ts | 2 +- .../root/EventScreen/addToCalendar.ts | 4 ++-- .../NotificationRow/NotificationRow.tsx | 2 +- .../NotificationRowContent.tsx | 8 +++---- .../NotificationScreen/NotificationScreen.tsx | 4 ++-- .../NotificationSectionHeader.tsx | 2 +- .../root/NotificationScreen/refresh.ts | 4 ++-- .../root/ProfileScreen/ProfileFooter.tsx | 4 ++-- .../root/ProfileScreen/ProfileScreen.tsx | 4 ++-- .../mobile/src/navigation/root/RootScreen.tsx | 2 +- .../tab/EventListScreen/EventListPage.tsx | 2 +- .../EventListScreen/EventListRenderItem.tsx | 4 ++-- .../tab/EventListScreen/eventListUtils.ts | 4 ++-- .../tab/ExplorerScreen/useExplorerFeed.tsx | 2 +- .../MarathonScreen/HourScreenComponent.tsx | 4 ++-- .../tab/MarathonScreen/MarathonScreen.tsx | 2 +- .../ScoreBoardScreen/ScoreBoardScreen.tsx | 4 ++-- .../root/tab/spirit/SpiritStack.tsx | 2 +- .../root/tab/spirit/TeamScreen/TeamScreen.tsx | 4 ++-- packages/mobile/src/types/navigationTypes.ts | 2 +- packages/portal/src/config/marathon.tsx | 2 +- .../src/elements/components/ImagePicker.tsx | 2 +- .../src/elements/components/PersonSearch.tsx | 2 +- .../notification/SingleNotificationGQL.ts | 2 +- .../create/CreateNotificationGQL.ts | 2 +- .../create/useNotificationCreator.ts | 2 +- .../manage/ManageNotificationForm.tsx | 4 ++-- .../manage/NotificationManagerGQL.ts | 2 +- .../elements/forms/person/PersonFormsGQL.ts | 2 +- .../forms/person/create/PersonCreator.tsx | 4 ++-- .../forms/person/create/PersonCreatorGQL.ts | 2 +- .../person/create/usePersonCreatorForm.ts | 4 ++-- .../forms/person/edit/PersonEditor.tsx | 4 ++-- .../forms/person/edit/PersonEditorGQL.ts | 2 +- .../forms/person/edit/usePersonEditorForm.ts | 6 ++--- .../create/PointEntryCreatorGQL.ts | 2 +- .../create/PointEntryOpportunityLookup.tsx | 4 ++-- .../create/usePointEntryCreatorForm.ts | 2 +- .../forms/team/create/TeamCreatorGQL.ts | 2 +- .../forms/team/create/useTeamCreatorForm.ts | 4 ++-- .../elements/forms/team/edit/TeamEditor.tsx | 4 ++-- .../elements/forms/team/edit/TeamEditorGQL.ts | 2 +- .../forms/team/edit/useTeamEditorForm.ts | 6 ++--- .../src/elements/tables/PeopleTable.tsx | 2 +- .../portal/src/elements/tables/TeamsTable.tsx | 2 +- .../NotificationDeliveriesTable.tsx | 2 +- .../notification/NotificationsTable.tsx | 2 +- .../point-entry/PointEntryDeletePopup.tsx | 2 +- .../tables/point-entry/PointEntryTable.tsx | 4 ++-- .../notification/NotificationViewer.tsx | 4 ++-- .../viewers/person/PersonDeletePopup.tsx | 2 +- .../elements/viewers/person/PersonViewer.tsx | 4 ++-- .../elements/viewers/team/TeamDeletePopup.tsx | 2 +- .../src/elements/viewers/team/TeamViewer.tsx | 4 ++-- packages/portal/src/hooks/useLoginState.ts | 2 +- .../src/pages/config/useCommitChanges.tsx | 2 +- packages/portal/src/pages/config/useConfig.ts | 2 +- .../events/create-event/EventCreatorGQL.ts | 2 +- .../create-event/useEventCreatorForm.ts | 2 +- .../pages/events/list-events/EventsTable.tsx | 2 +- .../single-event/edit-event/EditEventPage.tsx | 2 +- .../single-event/edit-event/EventEditor.tsx | 4 ++-- .../single-event/edit-event/EventEditorGQL.ts | 2 +- .../edit-event/useEventEditorForm.ts | 6 ++--- .../view-event/EventDeletePopup.tsx | 2 +- .../single-event/view-event/EventViewer.tsx | 4 ++-- .../single-event/view-event/ViewEventPage.tsx | 2 +- packages/portal/src/pages/feed/FeedPage.tsx | 2 +- .../pages/images/list/CreateImagePopup.tsx | 2 +- .../src/pages/images/list/ImagesTable.tsx | 2 +- .../marathon/create/useMarathonCreatorForm.ts | 2 +- .../overview/MarathonOverviewPage.tsx | 2 +- .../marathon/overview/MarathonsTable.tsx | 4 ++-- .../single/edit/useMarathonEditorForm.ts | 2 +- .../marathon/single/view/MarathonViewer.tsx | 4 ++-- .../marathon/single/view/ViewMarathonPage.tsx | 2 +- .../view/hour/add/AddMarathonHourPage.tsx | 2 +- .../view/hour/edit/EditMarathonHourPage.tsx | 2 +- .../single/manage/ManageNotificationPage.tsx | 2 +- .../single/view/ViewNotificationPage.tsx | 2 +- .../people/create-person/CreatePersonPage.tsx | 2 +- .../edit-person/EditPersonPage.tsx | 2 +- .../view-person/ViewPersonPage.tsx | 2 +- .../single-team/edit-team/EditTeamPage.tsx | 2 +- .../fundraising/ViewTeamFundraising.tsx | 2 +- .../view-team/teamPageDocument.tsx | 2 +- 106 files changed, 145 insertions(+), 144 deletions(-) rename packages/common/lib/{graphql-client-admin => graphql-client-mobile}/fragment-masking.ts (100%) rename packages/common/lib/{graphql-client-public => graphql-client-mobile}/gql.ts (100%) rename packages/common/lib/{graphql-client-public => graphql-client-mobile}/graphql.ts (100%) rename packages/common/lib/{graphql-client-admin => graphql-client-mobile}/index.ts (100%) rename packages/common/lib/{graphql-client-public => graphql-client-portal}/fragment-masking.ts (100%) rename packages/common/lib/{graphql-client-admin => graphql-client-portal}/gql.ts (100%) rename packages/common/lib/{graphql-client-admin => graphql-client-portal}/graphql.ts (100%) rename packages/common/lib/{graphql-client-public => graphql-client-portal}/index.ts (100%) diff --git a/codegen.ts b/codegen.ts index dcafda45..106799f9 100644 --- a/codegen.ts +++ b/codegen.ts @@ -59,7 +59,7 @@ const config: TypeScriptPluginConfig = { const generates: CodegenConfig["generates"] = {}; const packages = readdirSync("./packages"); if (packages.includes("mobile")) { - generates["./packages/common/lib/graphql-client-public/"] = { + generates["./packages/common/lib/graphql-client-mobile/"] = { preset: "client", presetConfig, config, @@ -70,7 +70,7 @@ if (packages.includes("mobile")) { }; } if (packages.includes("portal")) { - generates["./packages/common/lib/graphql-client-internal/"] = { + generates["./packages/common/lib/graphql-client-portal/"] = { preset: "client", presetConfig, config, diff --git a/packages/common/lib/graphql-client-admin/fragment-masking.ts b/packages/common/lib/graphql-client-mobile/fragment-masking.ts similarity index 100% rename from packages/common/lib/graphql-client-admin/fragment-masking.ts rename to packages/common/lib/graphql-client-mobile/fragment-masking.ts diff --git a/packages/common/lib/graphql-client-public/gql.ts b/packages/common/lib/graphql-client-mobile/gql.ts similarity index 100% rename from packages/common/lib/graphql-client-public/gql.ts rename to packages/common/lib/graphql-client-mobile/gql.ts diff --git a/packages/common/lib/graphql-client-public/graphql.ts b/packages/common/lib/graphql-client-mobile/graphql.ts similarity index 100% rename from packages/common/lib/graphql-client-public/graphql.ts rename to packages/common/lib/graphql-client-mobile/graphql.ts diff --git a/packages/common/lib/graphql-client-admin/index.ts b/packages/common/lib/graphql-client-mobile/index.ts similarity index 100% rename from packages/common/lib/graphql-client-admin/index.ts rename to packages/common/lib/graphql-client-mobile/index.ts diff --git a/packages/common/lib/graphql-client-public/fragment-masking.ts b/packages/common/lib/graphql-client-portal/fragment-masking.ts similarity index 100% rename from packages/common/lib/graphql-client-public/fragment-masking.ts rename to packages/common/lib/graphql-client-portal/fragment-masking.ts diff --git a/packages/common/lib/graphql-client-admin/gql.ts b/packages/common/lib/graphql-client-portal/gql.ts similarity index 100% rename from packages/common/lib/graphql-client-admin/gql.ts rename to packages/common/lib/graphql-client-portal/gql.ts diff --git a/packages/common/lib/graphql-client-admin/graphql.ts b/packages/common/lib/graphql-client-portal/graphql.ts similarity index 100% rename from packages/common/lib/graphql-client-admin/graphql.ts rename to packages/common/lib/graphql-client-portal/graphql.ts diff --git a/packages/common/lib/graphql-client-public/index.ts b/packages/common/lib/graphql-client-portal/index.ts similarity index 100% rename from packages/common/lib/graphql-client-public/index.ts rename to packages/common/lib/graphql-client-portal/index.ts diff --git a/packages/common/package.json b/packages/common/package.json index 05bff70a..0590d9ac 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -24,23 +24,24 @@ "node": "./dist/error/index.js", "default": null }, - "./graphql-client-admin": { + "./graphql-client-portal": { "node": null, "react-native": null, - "types": "./dist/graphql-client-admin/index.d.ts", - "default": "./dist/graphql-client-admin/index.js" + "types": "./dist/graphql-client-portal/index.d.ts", + "default": "./dist/graphql-client-portal/index.js" }, - "./graphql-client-public": { + "./graphql-client-mobile": { "node": null, - "react-native": "./dist/graphql-client-public/index.js", - "types": "./dist/graphql-client-public/index.d.ts", - "default": "./dist/graphql-client-public/index.js" + "browser": null, + "react-native": "./dist/graphql-client-mobile/index.js", + "types": "./dist/graphql-client-mobile/index.d.ts", + "default": "./dist/graphql-client-mobile/index.js" }, - "./graphql-client-admin/raw-types": { - "types": "./dist/graphql-client-admin/graphql.d.ts" + "./graphql-client-portal/raw-types": { + "types": "./dist/graphql-client-portal/graphql.d.ts" }, - "./graphql-client-public/raw-types": { - "types": "./dist/graphql-client-public/graphql.d.ts" + "./graphql-client-mobile/raw-types": { + "types": "./dist/graphql-client-mobile/graphql.d.ts" } }, "main": "./dist/index.js", diff --git a/packages/mobile/src/common/components/ImageView/ImageView.tsx b/packages/mobile/src/common/components/ImageView/ImageView.tsx index de83f3ec..22c99008 100644 --- a/packages/mobile/src/common/components/ImageView/ImageView.tsx +++ b/packages/mobile/src/common/components/ImageView/ImageView.tsx @@ -1,8 +1,8 @@ -import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; +import type { FragmentType } from "@ukdanceblue/common/graphql-client-mobile"; import { getFragmentData, graphql, -} from "@ukdanceblue/common/dist/graphql-client-public"; +} from "@ukdanceblue/common/graphql-client-mobile"; import { Image, type ImageProps } from "expo-image"; export const ImageViewFragment = graphql(/* GraphQL */ ` diff --git a/packages/mobile/src/common/fragments/Configuration.ts b/packages/mobile/src/common/fragments/Configuration.ts index 3db382d7..804dacf9 100644 --- a/packages/mobile/src/common/fragments/Configuration.ts +++ b/packages/mobile/src/common/fragments/Configuration.ts @@ -1,4 +1,4 @@ -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; export const SimpleConfigFragment = graphql(/* GraphQL */ ` fragment SimpleConfig on ConfigurationNode { diff --git a/packages/mobile/src/common/fragments/NotificationScreenGQL.ts b/packages/mobile/src/common/fragments/NotificationScreenGQL.ts index a6597f0d..bcee6d59 100644 --- a/packages/mobile/src/common/fragments/NotificationScreenGQL.ts +++ b/packages/mobile/src/common/fragments/NotificationScreenGQL.ts @@ -1,4 +1,4 @@ -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; export const NotificationFragment = graphql(/* GraphQL */ ` fragment NotificationFragment on NotificationNode { diff --git a/packages/mobile/src/common/hooks/useAllowedLoginTypes.ts b/packages/mobile/src/common/hooks/useAllowedLoginTypes.ts index 67ad10e1..730076d0 100644 --- a/packages/mobile/src/common/hooks/useAllowedLoginTypes.ts +++ b/packages/mobile/src/common/hooks/useAllowedLoginTypes.ts @@ -4,7 +4,7 @@ import type { UserLoginType } from "@context/user"; import { getFragmentData, graphql, -} from "@ukdanceblue/common/dist/graphql-client-public"; +} from "@ukdanceblue/common/graphql-client-mobile"; import { useEffect, useMemo } from "react"; import { useQuery } from "urql"; diff --git a/packages/mobile/src/common/hooks/useMarathonTime.ts b/packages/mobile/src/common/hooks/useMarathonTime.ts index 61218cc7..918838a0 100644 --- a/packages/mobile/src/common/hooks/useMarathonTime.ts +++ b/packages/mobile/src/common/hooks/useMarathonTime.ts @@ -1,6 +1,6 @@ import { Logger } from "@common/logger/Logger"; import { dateTimeFromSomething } from "@ukdanceblue/common"; -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; import { DateTime } from "luxon"; import { useEffect, useMemo } from "react"; import { useQuery } from "urql"; diff --git a/packages/mobile/src/common/hooks/useTabBarConfig.ts b/packages/mobile/src/common/hooks/useTabBarConfig.ts index 9e600c1e..6627a60d 100644 --- a/packages/mobile/src/common/hooks/useTabBarConfig.ts +++ b/packages/mobile/src/common/hooks/useTabBarConfig.ts @@ -3,7 +3,7 @@ import { Logger } from "@common/logger/Logger"; import { getFragmentData, graphql, -} from "@ukdanceblue/common/dist/graphql-client-public"; +} from "@ukdanceblue/common/graphql-client-mobile"; import { useEffect, useMemo } from "react"; import { useQuery } from "urql"; diff --git a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx index 570e5507..50ad257e 100644 --- a/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx +++ b/packages/mobile/src/common/marathonComponents/TriviaCrack.tsx @@ -4,7 +4,7 @@ import { TeamType } from "@ukdanceblue/common"; import { getFragmentData, graphql, -} from "@ukdanceblue/common/dist/graphql-client-public"; +} from "@ukdanceblue/common/graphql-client-mobile"; import { Text, View } from "native-base"; import { useEffect, useMemo, useState } from "react"; import { ActivityIndicator } from "react-native"; diff --git a/packages/mobile/src/context/auth.tsx b/packages/mobile/src/context/auth.tsx index 475f8bf3..eed7faa1 100644 --- a/packages/mobile/src/context/auth.tsx +++ b/packages/mobile/src/context/auth.tsx @@ -1,6 +1,6 @@ import { Logger } from "@common/logger/Logger"; import { AuthSource } from "@ukdanceblue/common"; -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; import type { ReactNode } from "react"; import { createContext, useContext, useEffect } from "react"; import { useQuery } from "urql"; diff --git a/packages/mobile/src/context/device.tsx b/packages/mobile/src/context/device.tsx index 7b189686..ebb8669d 100644 --- a/packages/mobile/src/context/device.tsx +++ b/packages/mobile/src/context/device.tsx @@ -1,7 +1,7 @@ import { useNetworkStatus } from "@common/customHooks"; import { Logger } from "@common/logger/Logger"; import { arrayToBase64String } from "@ukdanceblue/common"; -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; import { CryptoDigestAlgorithm, CryptoEncoding, diff --git a/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx b/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx index fa900fe3..2d27f14c 100644 --- a/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx +++ b/packages/mobile/src/navigation/root/EventScreen/EventScreen.tsx @@ -3,7 +3,7 @@ import { log } from "@common/logging"; import { showMessage } from "@common/util/alertUtils"; import { useRoute } from "@react-navigation/native"; import { intervalFromSomething } from "@ukdanceblue/common"; -import { getFragmentData } from "@ukdanceblue/common/dist/graphql-client-public"; +import { getFragmentData } from "@ukdanceblue/common/graphql-client-mobile"; import { setStringAsync } from "expo-clipboard"; import type { Interval } from "luxon"; import { DateTime } from "luxon"; diff --git a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts index a1b951da..cc68ae11 100644 --- a/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts +++ b/packages/mobile/src/navigation/root/EventScreen/EventScreenFragment.ts @@ -1,4 +1,4 @@ -import { graphql } from "@ukdanceblue/common/dist/graphql-client-public"; +import { graphql } from "@ukdanceblue/common/graphql-client-mobile"; export const EventScreenFragment = graphql(/* GraphQL */ ` fragment EventScreenFragment on EventNode { diff --git a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts index 92573d34..4e7488b3 100644 --- a/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts +++ b/packages/mobile/src/navigation/root/EventScreen/addToCalendar.ts @@ -2,8 +2,8 @@ import { universalCatch } from "@common/logging"; import { showMessage, showPrompt } from "@common/util/alertUtils"; import { discoverDefaultCalendar } from "@common/util/calendar"; import { intervalFromSomething } from "@ukdanceblue/common"; -import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; -import { getFragmentData } from "@ukdanceblue/common/dist/graphql-client-public"; +import type { FragmentType } from "@ukdanceblue/common/graphql-client-mobile"; +import { getFragmentData } from "@ukdanceblue/common/graphql-client-mobile"; import type { Event } from "expo-calendar"; import { PermissionStatus, diff --git a/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRow.tsx b/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRow.tsx index 27756ebd..79dccfd6 100644 --- a/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRow.tsx +++ b/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRow.tsx @@ -1,6 +1,6 @@ import type { NotificationDeliveryFragment } from "@common/fragments/NotificationScreenGQL"; import { showMessage } from "@common/util/alertUtils"; -import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; +import type { FragmentType } from "@ukdanceblue/common/graphql-client-mobile"; import { Box, Button, Row, useTheme } from "native-base"; import type { SectionListRenderItem } from "react-native"; import { useWindowDimensions } from "react-native"; diff --git a/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRowContent.tsx b/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRowContent.tsx index 26052899..c1bc7ff7 100644 --- a/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRowContent.tsx +++ b/packages/mobile/src/navigation/root/NotificationScreen/NotificationRow/NotificationRowContent.tsx @@ -4,8 +4,8 @@ import { NotificationFragment, } from "@common/fragments/NotificationScreenGQL"; import { Logger } from "@common/logger/Logger"; -import type { FragmentType } from "@ukdanceblue/common/dist/graphql-client-public"; -import { getFragmentData } from "@ukdanceblue/common/dist/graphql-client-public"; +import type { FragmentType } from "@ukdanceblue/common/graphql-client-mobile"; +import { getFragmentData } from "@ukdanceblue/common/graphql-client-mobile"; import { openURL } from "expo-linking"; import { isEqual } from "lodash"; import { DateTime } from "luxon"; @@ -54,8 +54,8 @@ const NonMemoizedNotificationRowContent = ({ deliveryFragmentData?.sentAt == null ? null : typeof deliveryFragmentData.sentAt === "string" - ? DateTime.fromISO(deliveryFragmentData.sentAt) - : DateTime.fromJSDate(deliveryFragmentData.sentAt); + ? DateTime.fromISO(deliveryFragmentData.sentAt) + : DateTime.fromJSDate(deliveryFragmentData.sentAt); return (