From 24b1b4ee13e46f688682ca29a5c276f3e5d027b1 Mon Sep 17 00:00:00 2001 From: Marc Buma Date: Tue, 2 Apr 2024 11:54:49 +0200 Subject: [PATCH 1/4] Add debian binary target for prisma --- prisma/schema.prisma | 66 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aa3180f..ee4066e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,6 +1,6 @@ generator client { provider = "prisma-client-js" - binaryTargets = ["native", "linux-musl-openssl-3.0.x"] + binaryTargets = ["native", "linux-musl-openssl-3.0.x", "debian-openssl-3.0.x"] } datasource db { @@ -2027,46 +2027,46 @@ enum accounts_account_type { // } model Account { - id String @id @default(cuid()) - userId String - type String - provider String - providerAccountId String - refresh_token String? @db.Text - access_token String? @db.Text - expires_at Int? - token_type String? - scope String? - id_token String? @db.Text - session_state String? - - user User @relation(fields: [userId], references: [id], onDelete: Cascade) - - @@unique([provider, providerAccountId]) + id String @id @default(cuid()) + userId String + type String + provider String + providerAccountId String + refresh_token String? @db.Text + access_token String? @db.Text + expires_at Int? + token_type String? + scope String? + id_token String? @db.Text + session_state String? + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) } model Session { - id String @id @default(cuid()) - sessionToken String @unique - userId String - expires DateTime - user User @relation(fields: [userId], references: [id], onDelete: Cascade) + id String @id @default(cuid()) + sessionToken String @unique + userId String + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { - id String @id @default(cuid()) - name String? - email String? @unique - emailVerified DateTime? - image String? - accounts Account[] - sessions Session[] + id String @id @default(cuid()) + name String? + email String? @unique + emailVerified DateTime? + image String? + accounts Account[] + sessions Session[] } model VerificationToken { - identifier String - token String @unique - expires DateTime + identifier String + token String @unique + expires DateTime - @@unique([identifier, token]) + @@unique([identifier, token]) } From 0c19062f67d863b98d4a5c2667e343fe85bce5fb Mon Sep 17 00:00:00 2001 From: bartwr Date: Wed, 3 Apr 2024 17:10:53 +0200 Subject: [PATCH 2/4] WIP Add magic email link signin --- .../migration.sql | 509 ++++++++++++++++++ src/pages/api/auth/[...nextauth].ts | 59 +- src/pages/login.tsx | 16 +- src/pages/login/verify-request.tsx | 149 +++++ 4 files changed, 702 insertions(+), 31 deletions(-) create mode 100644 prisma/migrations/20240402104252_add_magic_sign_in_models/migration.sql create mode 100644 src/pages/login/verify-request.tsx diff --git a/prisma/migrations/20240402104252_add_magic_sign_in_models/migration.sql b/prisma/migrations/20240402104252_add_magic_sign_in_models/migration.sql new file mode 100644 index 0000000..954c6e6 --- /dev/null +++ b/prisma/migrations/20240402104252_add_magic_sign_in_models/migration.sql @@ -0,0 +1,509 @@ +-- CreateTable +CREATE TABLE `abonnementsvorm_fietsenstalling` ( + `SubscriptiontypeID` INTEGER NOT NULL, + `BikeparkID` VARCHAR(35) NOT NULL, + + UNIQUE INDEX `SubscriptiontypeID`(`SubscriptiontypeID`, `BikeparkID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `abonnementsvormen` ( + `ID` INTEGER NOT NULL AUTO_INCREMENT, + `naam` VARCHAR(255) NULL, + `omschrijving` LONGTEXT NULL, + `prijs` DECIMAL(8, 2) NULL, + `tijdsduur` INTEGER NULL, + `conditions` TEXT NULL, + `siteID` VARCHAR(36) NULL, + `bikeparkTypeID` VARCHAR(15) NULL, + `isActief` BIT(1) NOT NULL DEFAULT b'1', + `exploitantSiteID` VARCHAR(36) NULL, + `idmiddelen` VARCHAR(40) NOT NULL DEFAULT 'sleutelhanger', + `contractID` VARCHAR(35) NULL, + `paymentAuthorizationID` VARCHAR(35) NULL, + `conditionsID` VARCHAR(255) NULL, + + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `abonnementsvorm_fietstype` ( + `SubscriptiontypeID` INTEGER NOT NULL, + `BikeTypeID` INTEGER NOT NULL, + + UNIQUE INDEX `prismaID`(`SubscriptiontypeID`, `BikeTypeID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `accounts` ( + `ID` VARCHAR(35) NOT NULL DEFAULT '', + `Email` VARCHAR(100) NULL, + `EncryptedPassword` VARCHAR(60) NULL, + `Sex` VARCHAR(10) NULL, + `FirstName` VARCHAR(100) NULL, + `MiddleName` VARCHAR(50) NULL, + `LastName` VARCHAR(100) NULL, + `Address` VARCHAR(255) NULL, + `Address_Nr` VARCHAR(10) NULL, + `Zip` VARCHAR(10) NULL, + `City` VARCHAR(100) NULL, + `Phone` VARCHAR(50) NULL, + `Mobile` VARCHAR(50) NULL, + `Nieuwsbrief` VARCHAR(4) NULL, + `Status` VARCHAR(4) NULL DEFAULT '1', + `DateRegistration` DATETIME(0) NULL, + `LastLogin` DATETIME(0) NULL, + `DateDeleted` DATETIME(0) NULL, + `saldo` DECIMAL(10, 2) NULL DEFAULT 0.00, + `account_type` ENUM('SYSTEM', 'USER', 'DELETED') NULL DEFAULT 'USER', + `dateLastSaldoUpdate` TIMESTAMP(0) NULL, + `dateLastPrize` DATETIME(0) NULL, + `nameLastPrize` VARCHAR(255) NULL, + + UNIQUE INDEX `Email_2`(`Email`), + INDEX `dateLastSaldoUpdate`(`dateLastSaldoUpdate`), + INDEX `saldo`(`saldo`), + INDEX `Email`(`Email`), + INDEX `EncryptedPassword`(`EncryptedPassword`), + INDEX `LastName`(`LastName`), + INDEX `account_type`(`account_type`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `articles` ( + `ID` VARCHAR(35) NOT NULL DEFAULT '', + `SiteID` VARCHAR(35) NULL, + `Language` VARCHAR(25) NULL, + `ParentID` VARCHAR(35) NULL, + `Title` VARCHAR(100) NULL, + `DisplayTitle` VARCHAR(100) NULL, + `Abstract` TEXT NULL, + `Article` TEXT NULL, + `CustomField1_Title` VARCHAR(255) NULL, + `CustomField1` TEXT NULL, + `Banner` VARCHAR(255) NULL, + `Keywords` TEXT NULL, + `SortOrder` INTEGER NULL, + `PublishStartDate` DATETIME(0) NULL, + `PublishEndDate` DATETIME(0) NULL, + `Status` VARCHAR(4) NULL DEFAULT '1', + `Navigation` VARCHAR(50) NULL, + `ShowInNav` VARCHAR(4) NULL, + `System` VARCHAR(4) NULL DEFAULT '0', + `EditorCreated` VARCHAR(255) NULL, + `DateCreated` DATETIME(0) NULL, + `EditorModified` VARCHAR(255) NULL, + `DateModified` DATETIME(0) NULL, + `ModuleID` VARCHAR(50) NOT NULL DEFAULT 'veiligstallen', + + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `contacts` ( + `ID` VARCHAR(35) NOT NULL DEFAULT '', + `ItemType` VARCHAR(20) NULL, + `GroupID` VARCHAR(20) NULL, + `ParentID` VARCHAR(35) NULL, + `ZipID` VARCHAR(4) NULL, + `Gemeentecode` INTEGER NULL, + `Paslezer` VARCHAR(20) NULL, + `PassRange_validate` VARCHAR(4) NULL, + `PassRange_start` BIGINT NULL, + `PassRange_end` BIGINT NULL, + `LockNGo` VARCHAR(4) NULL, + `Helpdesk` VARCHAR(255) NULL DEFAULT '', + `CompanyName` VARCHAR(100) NULL, + `AlternativeCompanyName` VARCHAR(100) NULL, + `UrlName` VARCHAR(100) NULL, + `CompanyLogo` VARCHAR(255) NULL, + `CompanyLogo2` VARCHAR(255) NULL, + `Department` VARCHAR(255) NULL, + `JobTitle` VARCHAR(255) NULL, + `Sex` VARCHAR(10) NULL, + `Title` VARCHAR(100) NULL, + `Initials` VARCHAR(100) NULL, + `FirstName` VARCHAR(255) NULL, + `MiddleName` VARCHAR(50) NULL, + `LastName` VARCHAR(255) NULL, + `Address1` VARCHAR(255) NULL, + `Address2` VARCHAR(255) NULL, + `Zip1` VARCHAR(10) NULL, + `Zip2` VARCHAR(10) NULL, + `City1` VARCHAR(255) NULL, + `City2` VARCHAR(255) NULL, + `Country1` VARCHAR(50) NULL, + `Country2` VARCHAR(50) NULL, + `Phone1` VARCHAR(50) NULL, + `Phone2` VARCHAR(50) NULL, + `Mobile1` VARCHAR(50) NULL, + `Mobile2` VARCHAR(50) NULL, + `Fax1` VARCHAR(50) NULL, + `Fax2` VARCHAR(50) NULL, + `Email1` VARCHAR(255) NULL, + `Email2` VARCHAR(255) NULL, + `URL` VARCHAR(255) NULL, + `Notes` TEXT NULL, + `Status` VARCHAR(4) NULL DEFAULT '1', + `Status_website` VARCHAR(4) NULL, + `DateRegistration` DATETIME(0) NULL, + `DateConfirmed` DATETIME(0) NULL, + `DateRejected` DATETIME(0) NULL, + `Winkansen_inzetten` VARCHAR(4) NULL, + `SendEmailOnSaldo` DECIMAL(8, 2) NULL, + `MinSaldoToUseLockers` DECIMAL(8, 2) NULL, + `MinSaldoToOpenLocker` DECIMAL(8, 2) NULL, + `Bankrekeningnr` VARCHAR(50) NULL, + `PlaatsBank` VARCHAR(100) NULL, + `Tnv` VARCHAR(100) NULL, + `Coordinaten` VARCHAR(100) NULL, + `Zoom` INTEGER NOT NULL DEFAULT 12, + `TextLeftColumn` TEXT NULL, + `TextRightColumn` TEXT NULL, + `DayBeginsAt` TIME(0) NOT NULL DEFAULT '00:00:00', + `ThemeColor1` VARCHAR(6) NOT NULL DEFAULT '1f99d2', + `ThemeColor2` VARCHAR(6) NOT NULL DEFAULT '96c11f', + `btwNummer` VARCHAR(50) NULL, + `kvkNummer` VARCHAR(50) NULL, + `durationOfLockerTempStatus` INTEGER NOT NULL DEFAULT 20, + `Password` VARCHAR(52) NULL, + + UNIQUE INDEX `ZipID`(`ZipID`), + UNIQUE INDEX `UrlName`(`UrlName`), + INDEX `CompanyName`(`CompanyName`), + INDEX `ItemType_idx`(`ItemType`), + UNIQUE INDEX `ItemType`(`ItemType`, `CompanyName`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `contacts_faq` ( + `ID` INTEGER NOT NULL AUTO_INCREMENT, + `SiteID` VARCHAR(36) NOT NULL, + `FaqID` VARCHAR(36) NOT NULL, + `Status` BIT(1) NOT NULL DEFAULT b'0', + + INDEX `FK4D3BB92A5CC39A7`(`FaqID`), + INDEX `FK4D3BB92A668AE523`(`SiteID`), + UNIQUE INDEX `SiteID`(`SiteID`, `FaqID`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `faq` ( + `ID` VARCHAR(35) NOT NULL DEFAULT '', + `ArticleID` VARCHAR(35) NULL, + `ParentID` VARCHAR(35) NULL, + `Title` VARCHAR(255) NULL, + `Description` VARCHAR(255) NULL, + `Question` TEXT NULL, + `Answer` TEXT NULL, + `SortOrder` INTEGER NULL, + `Status` VARCHAR(4) NULL DEFAULT '1', + `EditorCreated` VARCHAR(255) NULL, + `DateCreated` DATETIME(0) NULL, + `EditorModified` VARCHAR(255) NULL, + `DateModified` DATETIME(0) NULL, + `ModuleID` VARCHAR(50) NULL, + + INDEX `FK18B1665AC5B13`(`ModuleID`), + INDEX `FK18B16F3BE6D59`(`ParentID`), + INDEX `ArticleID`(`ArticleID`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `fietsenstalling_sectie` ( + `sectieId` INTEGER NOT NULL AUTO_INCREMENT, + `externalId` VARCHAR(13) NULL, + `titel` VARCHAR(255) NOT NULL, + `omschrijving` TEXT NULL, + `capaciteit` INTEGER NULL, + `CapaciteitBromfiets` INTEGER NULL, + `kleur` VARCHAR(6) NOT NULL DEFAULT '23B0D9', + `fietsenstallingsId` VARCHAR(35) NULL, + `isKluis` BIT(1) NOT NULL DEFAULT b'0', + `reserveringskostenPerDag` DOUBLE NULL, + `urlwebservice` VARCHAR(255) NULL, + `Reservable` BIT(1) NOT NULL DEFAULT b'0', + `NotaVerwijssysteem` TEXT NULL, + `Bezetting` INTEGER UNSIGNED NOT NULL DEFAULT 0, + `isactief` BIT(1) NOT NULL DEFAULT b'1', + `qualificatie` VARCHAR(255) NULL DEFAULT 'NONE', + + UNIQUE INDEX `externalId`(`externalId`), + INDEX `FKA8FBA192D2C0280D`(`fietsenstallingsId`), + INDEX `fietsenstallingsId`(`fietsenstallingsId`), + INDEX `isactief`(`isactief`), + PRIMARY KEY (`sectieId`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `fietsenstallingen` ( + `ID` VARCHAR(35) NOT NULL DEFAULT '', + `StallingsID` VARCHAR(8) NULL, + `SiteID` VARCHAR(35) NULL, + `Title` VARCHAR(255) NULL, + `StallingsIDExtern` VARCHAR(100) NULL, + `Description` TEXT NULL, + `Image` VARCHAR(255) NULL, + `Location` VARCHAR(255) NULL, + `Postcode` VARCHAR(7) NULL, + `Plaats` VARCHAR(100) NULL, + `Capacity` INTEGER NULL, + `Openingstijden` TEXT NULL, + `Status` VARCHAR(4) NULL DEFAULT '1', + `EditorCreated` VARCHAR(255) NULL, + `DateCreated` DATETIME(0) NULL, + `EditorModified` VARCHAR(255) NULL, + `DateModified` DATETIME(0) NULL, + `Ip` VARCHAR(24) NULL, + `Coordinaten` VARCHAR(255) NULL, + `geoLocation` point NULL, + `Type` VARCHAR(15) NULL, + `Verwijssysteem` BIT(1) NOT NULL DEFAULT b'0', + `VerwijssysteemOverzichten` BIT(1) NULL, + `FMS` BIT(1) NOT NULL DEFAULT b'0', + `Open_ma` TIME(0) NULL, + `Dicht_ma` TIME(0) NULL, + `Open_di` TIME(0) NULL, + `Dicht_di` TIME(0) NULL, + `Open_wo` TIME(0) NULL, + `Dicht_wo` TIME(0) NULL, + `Open_do` TIME(0) NULL, + `Dicht_do` TIME(0) NULL, + `Open_vr` TIME(0) NULL, + `Dicht_vr` TIME(0) NULL, + `Open_za` TIME(0) NULL, + `Dicht_za` TIME(0) NULL, + `Open_zo` TIME(0) NULL, + `Dicht_zo` TIME(0) NULL, + `OmschrijvingTarieven` TEXT NULL, + `IsStationsstalling` BIT(1) NOT NULL DEFAULT b'0', + `IsPopup` BIT(1) NOT NULL DEFAULT b'0', + `NotaVerwijssysteem` TEXT NULL, + `Tariefcode` INTEGER NULL, + `Toegangscontrole` INTEGER NULL, + `Beheerder` VARCHAR(100) NULL, + `BeheerderContact` VARCHAR(255) NULL, + `Url` TEXT NULL, + `ExtraServices` TEXT NULL, + `dia` TEXT NULL, + `BerekentStallingskosten` BIT(1) NOT NULL DEFAULT b'0', + `AantalReserveerbareKluizen` INTEGER NOT NULL DEFAULT 0, + `MaxStallingsduur` INTEGER NOT NULL DEFAULT 0, + `HeeftExterneBezettingsdata` BIT(1) NOT NULL DEFAULT b'0', + `ExploitantID` VARCHAR(35) NULL, + `hasUniSectionPrices` BIT(1) NOT NULL DEFAULT b'1', + `hasUniBikeTypePrices` BIT(1) NOT NULL DEFAULT b'0', + `shadowBikeparkID` VARCHAR(35) NULL, + `BronBezettingsdata` VARCHAR(20) NULL DEFAULT 'FMS', + `reservationCostPerDay` DECIMAL(8, 2) NULL, + `wachtlijst_Id` BIGINT NULL, + `freeHoursReservation` DECIMAL(8, 2) NULL, + `thirdPartyReservationsUrl` VARCHAR(255) NULL, + + UNIQUE INDEX `idxstallingsid`(`StallingsID`), + INDEX `idxSiteidstid`(`StallingsID`, `SiteID`), + INDEX `sidxsiteid`(`SiteID`), + INDEX `ExploitantID`(`ExploitantID`), + INDEX `FKF4836A55668AE523`(`SiteID`), + INDEX `shadowBikeparkID`(`shadowBikeparkID`), + INDEX `wachtlijst_Id`(`wachtlijst_Id`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `fietsenstallingen_services` ( + `ServiceID` VARCHAR(50) NOT NULL, + `FietsenstallingID` VARCHAR(35) NOT NULL, + + INDEX `FK4BB0A7082B597E32`(`FietsenstallingID`), + INDEX `FK4BB0A708CDE95925`(`ServiceID`), + PRIMARY KEY (`ServiceID`, `FietsenstallingID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `fietsenstallingtypen` ( + `id` VARCHAR(15) NOT NULL, + `name` VARCHAR(255) NULL, + `sequence` SMALLINT NOT NULL, + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `fietstypen` ( + `ID` INTEGER NOT NULL AUTO_INCREMENT, + `Name` VARCHAR(255) NULL, + `naamenkelvoud` VARCHAR(255) NOT NULL, + + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `sectie_fietstype` ( + `SectionBiketypeID` INTEGER NOT NULL AUTO_INCREMENT, + `Capaciteit` INTEGER NULL, + `Toegestaan` BIT(1) NULL, + `sectieID` INTEGER NULL, + `StallingsID` VARCHAR(35) NULL, + `BikeTypeID` INTEGER NULL, + + INDEX `sectieID`(`sectieID`), + INDEX `BikeTypeID`(`BikeTypeID`), + INDEX `StallingsID`(`StallingsID`), + UNIQUE INDEX `sectieID_2`(`sectieID`, `StallingsID`, `BikeTypeID`), + PRIMARY KEY (`SectionBiketypeID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `security_roles` ( + `RoleID` INTEGER NOT NULL AUTO_INCREMENT, + `GroupID` ENUM('intern', 'extern', 'exploitant', 'beheerder') NULL DEFAULT 'extern', + `Role` VARCHAR(50) NULL, + `Description` VARCHAR(150) NULL, + `Active` BOOLEAN NOT NULL DEFAULT true, + + PRIMARY KEY (`RoleID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `security_users` ( + `UserID` VARCHAR(35) NOT NULL DEFAULT '', + `Locale` VARCHAR(55) NULL DEFAULT 'Dutch (Standard)', + `RoleID` INTEGER NULL, + `GroupID` VARCHAR(20) NULL, + `SiteID` VARCHAR(35) NULL, + `ParentID` VARCHAR(35) NULL, + `UserName` VARCHAR(100) NULL, + `EncryptedPassword` VARCHAR(60) NULL, + `EncryptedPassword2` VARCHAR(255) NULL, + `DisplayName` VARCHAR(255) NULL, + `LastLogin` DATETIME(0) NULL, + `SendMailToMailAddress` VARCHAR(4) NULL, + `Theme` VARCHAR(50) NULL, + `Status` VARCHAR(4) NULL, + + INDEX `RoleID`(`RoleID`), + INDEX `UserName`(`UserName`), + UNIQUE INDEX `unique_userID_siteID`(`UserID`, `SiteID`), + PRIMARY KEY (`UserID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `security_users_sites` ( + `ID` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `UserID` VARCHAR(35) NOT NULL DEFAULT '', + `SiteID` VARCHAR(35) NOT NULL, + `IsContact` BIT(1) NOT NULL DEFAULT b'0', + + UNIQUE INDEX `UserID`(`UserID`, `SiteID`), + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `services` ( + `ID` VARCHAR(50) NOT NULL, + `Name` VARCHAR(255) NOT NULL, + + PRIMARY KEY (`ID`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Account` ( + `id` VARCHAR(191) NOT NULL, + `userId` VARCHAR(191) NOT NULL, + `type` VARCHAR(191) NOT NULL, + `provider` VARCHAR(191) NOT NULL, + `providerAccountId` VARCHAR(191) NOT NULL, + `refresh_token` TEXT NULL, + `access_token` TEXT NULL, + `expires_at` INTEGER NULL, + `token_type` VARCHAR(191) NULL, + `scope` VARCHAR(191) NULL, + `id_token` TEXT NULL, + `session_state` VARCHAR(191) NULL, + + UNIQUE INDEX `Account_provider_providerAccountId_key`(`provider`, `providerAccountId`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `Session` ( + `id` VARCHAR(191) NOT NULL, + `sessionToken` VARCHAR(191) NOT NULL, + `userId` VARCHAR(191) NOT NULL, + `expires` DATETIME(3) NOT NULL, + + UNIQUE INDEX `Session_sessionToken_key`(`sessionToken`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `User` ( + `id` VARCHAR(191) NOT NULL, + `name` VARCHAR(191) NULL, + `email` VARCHAR(191) NULL, + `emailVerified` DATETIME(3) NULL, + `image` VARCHAR(191) NULL, + + UNIQUE INDEX `User_email_key`(`email`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `VerificationToken` ( + `identifier` VARCHAR(191) NOT NULL, + `token` VARCHAR(191) NOT NULL, + `expires` DATETIME(3) NOT NULL, + + UNIQUE INDEX `VerificationToken_token_key`(`token`), + UNIQUE INDEX `VerificationToken_identifier_token_key`(`identifier`, `token`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `abonnementsvorm_fietsenstalling` ADD CONSTRAINT `abonnementsvorm_fietsenstalling_SubscriptiontypeID_fkey` FOREIGN KEY (`SubscriptiontypeID`) REFERENCES `abonnementsvormen`(`ID`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `abonnementsvorm_fietsenstalling` ADD CONSTRAINT `abonnementsvorm_fietsenstalling_BikeparkID_fkey` FOREIGN KEY (`BikeparkID`) REFERENCES `fietsenstallingen`(`ID`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `abonnementsvorm_fietstype` ADD CONSTRAINT `FK_avft_av` FOREIGN KEY (`BikeTypeID`) REFERENCES `abonnementsvormen`(`ID`) ON DELETE NO ACTION ON UPDATE RESTRICT; + +-- AddForeignKey +ALTER TABLE `abonnementsvorm_fietstype` ADD CONSTRAINT `FK_avft_ft` FOREIGN KEY (`SubscriptiontypeID`) REFERENCES `fietstypen`(`ID`) ON DELETE NO ACTION ON UPDATE RESTRICT; + +-- AddForeignKey +ALTER TABLE `fietsenstalling_sectie` ADD CONSTRAINT `fietsenstalling_sectie_fietsenstallingsId_fkey` FOREIGN KEY (`fietsenstallingsId`) REFERENCES `fietsenstallingen`(`ID`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `fietsenstallingen` ADD CONSTRAINT `fietsenstallingen_Type_fkey` FOREIGN KEY (`Type`) REFERENCES `fietsenstallingtypen`(`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `fietsenstallingen` ADD CONSTRAINT `FKCC75C0BE66279D19` FOREIGN KEY (`ExploitantID`) REFERENCES `contacts`(`ID`) ON DELETE RESTRICT ON UPDATE RESTRICT; + +-- AddForeignKey +ALTER TABLE `fietsenstallingen_services` ADD CONSTRAINT `FK_fietsenstallingen_service_fietsenstalling` FOREIGN KEY (`FietsenstallingID`) REFERENCES `fietsenstallingen`(`ID`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `fietsenstallingen_services` ADD CONSTRAINT `FK_fietsenstallingen_service_service` FOREIGN KEY (`ServiceID`) REFERENCES `services`(`ID`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `sectie_fietstype` ADD CONSTRAINT `FK_sectie_fietstype_sectie` FOREIGN KEY (`sectieID`) REFERENCES `fietsenstalling_sectie`(`sectieId`) ON DELETE NO ACTION ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `sectie_fietstype` ADD CONSTRAINT `FK_sectie_fietstype_fietstype` FOREIGN KEY (`BikeTypeID`) REFERENCES `fietstypen`(`ID`) ON DELETE NO ACTION ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `security_users` ADD CONSTRAINT `security_users_ibfk_1` FOREIGN KEY (`RoleID`) REFERENCES `security_roles`(`RoleID`) ON DELETE RESTRICT ON UPDATE RESTRICT; + +-- AddForeignKey +ALTER TABLE `security_users_sites` ADD CONSTRAINT `security_users_sites_ibfk_1` FOREIGN KEY (`UserID`) REFERENCES `security_users`(`UserID`) ON DELETE RESTRICT ON UPDATE RESTRICT; + +-- AddForeignKey +ALTER TABLE `Account` ADD CONSTRAINT `Account_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `Session` ADD CONSTRAINT `Session_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts index 0955a3e..8a06038 100644 --- a/src/pages/api/auth/[...nextauth].ts +++ b/src/pages/api/auth/[...nextauth].ts @@ -2,10 +2,10 @@ import { prisma } from "~/server/db"; import type { Provider } from "next-auth/providers"; import NextAuth from "next-auth"; -// import { PrismaAdapter } from "@auth/prisma-adapter" +import { PrismaAdapter } from "@auth/prisma-adapter" import type { NextAuthOptions, User } from "next-auth"; -// import EmailProvider from "next-auth/providers/email" +import EmailProvider from "next-auth/providers/email" import CredentialsProvider from "next-auth/providers/credentials"; @@ -40,39 +40,49 @@ providers.push( // eslint-disable-next-line @typescript-eslint/no-unused-vars req: Pick ): Promise { + console.log('== authorize called') const user = await getUserFromCredentials(credentials); return user; }, }), - // EmailProvider({ - // name: "Magic link", - // server: { - // host: process.env.EMAIL_SERVER_HOST, - // port: process.env.EMAIL_SERVER_PORT, - // auth: { - // user: process.env.EMAIL_SERVER_USER, - // pass: process.env.EMAIL_SERVER_PASSWORD - // } - // }, - // from: process.env.EMAIL_FROM, - // maxAge: 60 * 60, // 1 hour - // // sendVerificationRequest({ - // // identifier: email, - // // url, - // // provider: { server, from } - // // }) { - // // /* your function */ - // // } - // }) + EmailProvider({ + server: { + host: process.env.EMAIL_SERVER_HOST, + port: process.env.EMAIL_SERVER_PORT, + auth: { + user: process.env.EMAIL_SERVER_USER, + pass: process.env.EMAIL_SERVER_PASSWORD + }, + }, + from: process.env.EMAIL_FROM, + maxAge: 60 * 60, // 1 hour + // sendVerificationRequest({ + // identifier: email, + // url, + // provider: { server, from }, + // }) { + + // } + }) ); export const authOptions: NextAuthOptions = { + debug: true, + adapter: PrismaAdapter(prisma), providers, - // adapter: PrismaAdapter(prisma), // https://next-auth.js.org/configuration/callbacks callbacks: { + async signIn({ user, account, profile, email, credentials }) { + console.log('== SIGNIN called'); + if (account && account.provider === "email") { + return true; + } + return false; + }, + // augment jwt token with information that will be used on the server side async jwt({ user, token, account: accountParam }) { + console.log('== async jwt called') if (token && 'OrgUserID' in token === false && user) { token.OrgUserID = user.OrgUserID; } @@ -82,6 +92,7 @@ export const authOptions: NextAuthOptions = { // augment session with information that will be used on the client side async session({ session, token }) { + console.log('== async session({ session, token }) called') if (session?.user && token?.OrgUserID) { const account = await prisma.security_users.findFirst({ where: { UserID: token.OrgUserID } }); if (account) { @@ -112,6 +123,8 @@ export const authOptions: NextAuthOptions = { signIn: '/login', // signOut: '/', // error: '/login', // Error code passed in query string as ?error= + verifyRequest: '/auth/verify-request', // (used for check email message) + // newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest) }, }; diff --git a/src/pages/login.tsx b/src/pages/login.tsx index acc0da4..56f76d2 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -30,16 +30,16 @@ const Login: NextPage = () => { passwordRef.current && passwordRef.current.value !== '' ) { // console.log('signing in with magic link') - // signIn("email", { - // email: emailRef.current.value.trim(), - // // password: passwordRef.current.value, - // // callbackUrl: "/", - // }); - signIn("credentials", { + signIn("email", { email: emailRef.current.value.trim(), - password: passwordRef.current.value, - callbackUrl: "/", + // password: passwordRef.current.value, + // callbackUrl: "/", }); + // signIn("credentials", { + // email: emailRef.current.value.trim(), + // password: passwordRef.current.value, + // callbackUrl: "/", + // }); } else { alert('no email of password given'); } diff --git a/src/pages/login/verify-request.tsx b/src/pages/login/verify-request.tsx new file mode 100644 index 0000000..cfd9992 --- /dev/null +++ b/src/pages/login/verify-request.tsx @@ -0,0 +1,149 @@ +import React, { useRef } from "react"; +import { useRouter } from 'next/navigation' +import useQueryParam from '../../hooks/useQueryParam'; + +// import bcrypt from 'bcrypt' + +// Import utils +// import { getParkingsFromDatabase } from "~/utils/prisma"; + +// Import components +import PageTitle from "~/components/PageTitle"; +import FormInput from "~/components/Form/FormInput"; +import FormCheckbox from "~/components/Form/FormCheckbox"; +import AppHeaderDesktop from "~/components/AppHeaderDesktop"; +import { Button } from "~/components/Button"; +import { signIn } from "next-auth/react"; + + + +// import ImageSlider from "~/components/ImageSlider"; +// import HorizontalDivider from "~/components/HorizontalDivider"; +// import CloseButton from "~/components/CloseButton"; +// import Parking from "~/components/Parking"; + +import Styles from "./error.module.css"; +import { NextPage } from "next/types"; +import Head from "next/head"; +import AppHeader from "~/components/AppHeader"; + +const VerifyRequest: NextPage = () => { + + const router = useRouter() + const theError = useQueryParam("error")[0] || ''; + + const onConfirm = async (e: React.MouseEvent) => { + router.push('/login') + }; + + const renderError = (err: string): string => { + if (err === 'CredentialsSignin') { + return 'Controleer je inloggegevens' + } + return ''; + } + + return ( + <> + + + Login - VeiligStallen + + +
+ + + +
+ +
+
+ +
+
+
+ +
+
+ +
+ VeiligStallen logo + Open je mailbox +
+
+

+ {/* {renderError(theError)} */} + We hebben een inlog-link verstuurd naar je mailadres. Klik hierop om in te loggen. +

+
+
+ +
+ + + +
+
+ +
+
+ + ); +}; + +export default VerifyRequest; From 8ca3b0b0d04ce44e16950802baef7e0019373d6b Mon Sep 17 00:00:00 2001 From: Marc Buma Date: Thu, 4 Apr 2024 02:47:28 +0200 Subject: [PATCH 3/4] work in progress --- mysql-db/handy-queries.sql | 28 ++++++++++++++++ .../services/fietsenstallingen-service.ts | 32 +++++++++++++++++-- .../fietsenstallingen_services-service.ts | 8 +++-- src/components/parking/ParkingEdit.tsx | 19 +++++++---- .../parking/ParkingEditCapaciteit.tsx | 4 ++- src/components/parking/ParkingView.tsx | 6 ++-- .../parking/ParkingViewBeheerder.tsx | 26 ++++++++++----- .../parking/ParkingViewCapaciteit.tsx | 21 ++++++++---- .../parking/ParkingViewServices.tsx | 8 +++++ src/pages/api/auth/[...nextauth].ts | 2 +- src/pages/index.tsx | 1 - src/utils/parkings.tsx | 26 +++++++++++++++ 12 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 mysql-db/handy-queries.sql diff --git a/mysql-db/handy-queries.sql b/mysql-db/handy-queries.sql new file mode 100644 index 0000000..2bbfe70 --- /dev/null +++ b/mysql-db/handy-queries.sql @@ -0,0 +1,28 @@ +select UserID FROM security_users where UserName="mosbuma@bumos.nl" into @marc; +select ID From fietsenstallingen where Title like "%Marktstraat%" AND Plaats="Apeldoorn" INTO @stalling; +select @marc, @stalling; +INSERT INTO security_users_sites(UserID, SiteID, isContact) VALUES(@marc, @stalling, 0); + +select fs.title +from security_users_sites sus +JOIN fietsenstallingen fs ON (fs.ID=sus.SiteID) +where sus.UserID=@marc; + +Select * from fietsenstallingen_services where FietsenstallingID="0066B68F-6F95-4C42-BACF7B44C50FA061"; +Select * from fietsenstallingen where ID="0066B68F-6F95-4C42-BACF7B44C50FA061"; + +select ID, Title, Beheerder, BeheerderContact, Capacity from fietsenstallingen WHERE IsStationsstalling; +select * from fietsenstallingen WHERE ID="0066B68F-6F95-4C42-BACF7B44C50FA061"; + +select * from security_users_sites where UserID="D4351342-685D-D17A-B3617EEBBF39451C"; +select * from security_users_sites where UserID = @marc; + +select * from fietsenstalling_sectie where fietsenstallingsId=@SiteID; + +select fs.ID, fs.Title, fs.Plaats, fs.Capacity, count(fss.sectieId), sum(fss.capaciteit) +from fietsenstalling_sectie fss +left join fietsenstallingen fs ON fs.id=fss.fietsenstallingsId +WHERE fs.ID="0066B68F-6F95-4C42-BACF7B44C50FA061" +group by fs.ID +having count(fss.sectieId)>1 +order by fs.Plaats, fs.Title diff --git a/src/backend/services/fietsenstallingen-service.ts b/src/backend/services/fietsenstallingen-service.ts index 7ec5506..93ab822 100644 --- a/src/backend/services/fietsenstallingen-service.ts +++ b/src/backend/services/fietsenstallingen-service.ts @@ -2,13 +2,41 @@ import { prisma } from "~/server/db"; import type { fietsenstallingen } from "@prisma/client"; import type { ICrudService } from "~/backend/handlers/crud-service-interface"; +BigInt.prototype.toJSON = function () { + const int = Number.parseInt(this.toString()); + return int ?? this.toString(); +}; + +const include = { + fietsenstalling_secties: { + include: { + secties_fietstype: { + include: { fietstype: true } + } + } + }, + fietsenstallingen_services: { + include: { + services: true + } + } +} + // inspired by https://medium.com/@brandonlostboy/build-it-better-next-js-crud-api-b45d2e923896 const FietsenstallingenService: ICrudService = { getAll: async () => { - return await prisma.fietsenstallingen.findMany(); + return await prisma.fietsenstallingen.findMany({ + include: { + fietsenstalling_secties: true, + } + }); }, getOne: async (id: string) => { - return await prisma.fietsenstallingen.findFirst({ where: { ID: id } }); + return await prisma.fietsenstallingen.findFirst({ + where: { ID: id }, + include + } + ); }, create: async (_data: fietsenstallingen): Promise => { return await prisma.fietsenstallingen.create({ data: _data }); diff --git a/src/backend/services/fietsenstallingen_services-service.ts b/src/backend/services/fietsenstallingen_services-service.ts index 5b1af04..8d687ed 100644 --- a/src/backend/services/fietsenstallingen_services-service.ts +++ b/src/backend/services/fietsenstallingen_services-service.ts @@ -8,9 +8,11 @@ const FietsenstallingenServicesService: ICrudService return await prisma.fietsenstallingen_services.findMany(); }, getOne: async (fietsenstallingId: string) => { - return await prisma.fietsenstallingen_services.findFirst({ where: { - FietsenstallingID: fietsenstallingId - } }); + return await prisma.fietsenstallingen_services.findFirst({ + where: { + FietsenstallingID: fietsenstallingId + } + }); }, create: async (_data: fietsenstallingen_services): Promise => { return await prisma.fietsenstallingen_services.create({ data: _data }); diff --git a/src/components/parking/ParkingEdit.tsx b/src/components/parking/ParkingEdit.tsx index d61f599..36cef13 100644 --- a/src/components/parking/ParkingEdit.tsx +++ b/src/components/parking/ParkingEdit.tsx @@ -18,6 +18,8 @@ import { Tabs, Tab, FormHelperText, Typography } from "@mui/material"; /* Use nicely formatted items for items that can not be changed yet */ import ParkingViewTarief from "~/components/parking/ParkingViewTarief"; +import type { ServiceType } from "~/components/parking/ParkingViewServices"; + import ParkingViewAbonnementen from "~/components/parking/ParkingViewAbonnementen"; import ParkingEditCapaciteit, { type CapaciteitType } from "~/components/parking/ParkingEditCapaciteit"; import ParkingEditLocation from "~/components/parking/ParkingEditLocation"; @@ -36,8 +38,8 @@ export type ParkingEditUpdateStructure = { Postcode?: string; Plaats?: string; Coordinaten?: string; - DateCreated: Date; - DateModified: Date; + DateCreated?: Date; + DateModified?: Date; Type?: string; SiteID?: string; Beheerder?: string, @@ -48,7 +50,6 @@ export type ParkingEditUpdateStructure = { fietsenstalling_secties?: ParkingSections; // Replace with the actual type if different } -type ServiceType = { ID: string, Name: string }; type ChangedType = { ID: string, selected: boolean }; const NoClickOverlay = () => { @@ -237,11 +238,11 @@ const ParkingEdit = ({ parkingdata, onClose, onChange }: { parkingdata: ParkingD let checks: checkInfo[] = [ { type: "string", text: "invoer van de titel", value: parkingdata.Title, newvalue: newTitle }, { type: "string", text: "invoer van de straat en huisnummer", value: parkingdata.Location, newvalue: newLocation }, - { type: "string", text: "invoer van de postcode", value: parkingdata.Postcode, newvalue: newPostcode }, { type: "string", text: "invoer van de plaats", value: parkingdata.Plaats, newvalue: newPlaats }, { type: "string", text: "selectie van de gemeente", value: parkingdata.SiteID, newvalue: newSiteID }, { type: "coordinaten", text: "instellen van de locatie op de kaart", value: parkingdata.Coordinaten, newvalue: newCoordinaten }, ] + // parkingdata.Postcode is optional // FMS & ExploitantID cannot be changed for now, so no need to check those for changes if (parkingdata.FMS !== true && parkingdata.ExploitantID === null) { @@ -311,6 +312,7 @@ const ParkingEdit = ({ parkingdata, onClose, onChange }: { parkingdata: ParkingD if (!parkingdata.DateCreated) { update.DateCreated = today; } + update.DateModified = today; return update; @@ -363,6 +365,7 @@ const ParkingEdit = ({ parkingdata, onClose, onChange }: { parkingdata: ParkingD } const updateCapaciteit = async (parkingdata: ParkingDetailsType, newCapaciteit: ParkingSections) => { + console.log("update capaciteit", newCapaciteit); if (!newCapaciteit || newCapaciteit.length <= 0) return; try { @@ -541,8 +544,10 @@ const ParkingEdit = ({ parkingdata, onClose, onChange }: { parkingdata: ParkingD return; } + const method = isNew ? "POST" : "PUT"; const body = JSON.stringify(isNew ? Object.assign({}, parkingdata, update) : update); + console.log("update %s / %s", isNew, method, update); const result = await fetch( "/api/fietsenstallingen?id=" + parkingdata.ID, @@ -564,9 +569,9 @@ const ParkingEdit = ({ parkingdata, onClose, onChange }: { parkingdata: ParkingD } // If capaciteit is updated: Update capaciteit - if (newCapaciteit && newCapaciteit.length > 0) { - await updateCapaciteit(parkingdata, newCapaciteit); - } + // if (newCapaciteit && newCapaciteit.length > 0) { + // await updateCapaciteit(parkingdata, newCapaciteit); + // } let returnID: string | boolean = parkingdata.ID if (session === null) { diff --git a/src/components/parking/ParkingEditCapaciteit.tsx b/src/components/parking/ParkingEditCapaciteit.tsx index 56337ac..260cf92 100644 --- a/src/components/parking/ParkingEditCapaciteit.tsx +++ b/src/components/parking/ParkingEditCapaciteit.tsx @@ -151,7 +151,9 @@ const toggleActive = (fietsenstalling_secties: ParkingSections, fietstypeName: s const handleCapacityChange = (fietsenstalling_secties: ParkingSections, fietstypeName: any, amountstr: string): ParkingSections => { // It's mandatory to have at least 1 section - if (!fietsenstalling_secties) return fietsenstalling_secties; + if (!fietsenstalling_secties) { + return fietsenstalling_secties; + } if (!fietsenstalling_secties[0]) return fietsenstalling_secties; if (!fietsenstalling_secties[0].secties_fietstype) return fietsenstalling_secties; diff --git a/src/components/parking/ParkingView.tsx b/src/components/parking/ParkingView.tsx index c07c950..4af20ff 100644 --- a/src/components/parking/ParkingView.tsx +++ b/src/components/parking/ParkingView.tsx @@ -115,7 +115,7 @@ const ParkingView = ({ - {parkingdata.fietsenstalling_type?.name || "Onbekend"} + {parkingdata.Type || "Onbekend"} @@ -141,7 +141,7 @@ const ParkingView = ({ sm:absolute sm:bottom-1 " - onClick={(e) => { + onClick={(e: any) => { if (e) e.preventDefault(); openRoute(parkingdata.Coordinaten); }} @@ -158,7 +158,7 @@ const ParkingView = ({ - + ); }; diff --git a/src/components/parking/ParkingViewBeheerder.tsx b/src/components/parking/ParkingViewBeheerder.tsx index 62bfe08..d776fd6 100644 --- a/src/components/parking/ParkingViewBeheerder.tsx +++ b/src/components/parking/ParkingViewBeheerder.tsx @@ -4,21 +4,31 @@ import HorizontalDivider from "~/components/HorizontalDivider"; import SectionBlock from "~/components/SectionBlock"; const ParkingViewBeheerder = ({ parkingdata }: { parkingdata: any }) => { - // console.log("### ParkingViewBeheerder", parkingdata, parkingdata.Exploitant, parkingdata.Beheerder, parkingdata.BeheerderContact); - if (parkingdata.FMS === true) { - return FMS; - } else if(parkingdata?.exploitant) { + console.log("### ParkingViewBeheerder", parkingdata, parkingdata.Exploitant, parkingdata.Beheerder, parkingdata.BeheerderContact); + // if (parkingdata.FMS === true) { + // return FMS; + // } else + if (parkingdata?.exploitant) { return ( - {parkingdata.exploitant.CompanyName} + {parkingdata.exploitant.CompanyName} ) - } else if(parkingdata.BeheerderContact !== null) { + } else if (parkingdata.BeheerderContact !== null) { + let contactlink = ""; + if (parkingdata.BeheerderContact.includes("@")) { + contactlink = 'mailto:' + parkingdata.BeheerderContact + } else if (parkingdata.BeheerderContact.startsWith("http")) { + contactlink = parkingdata.BeheerderContact; + } else if (parkingdata.BeheerderContact.startsWith("www")) { + contactlink = 'https://' + parkingdata.BeheerderContact; + } + return ( - {parkingdata.Beheerder === null ? 'contact' : parkingdata.Beheerder} + {parkingdata.Beheerder === null ? parkingdata.BeheerderContact : parkingdata.Beheerder} - ); + ); } else { return null } diff --git a/src/components/parking/ParkingViewCapaciteit.tsx b/src/components/parking/ParkingViewCapaciteit.tsx index 00fcf2c..831426a 100644 --- a/src/components/parking/ParkingViewCapaciteit.tsx +++ b/src/components/parking/ParkingViewCapaciteit.tsx @@ -23,8 +23,11 @@ const calculateCapacityData = (parking: ParkingDetailsType): capacitydata | null detailed: {}, }; - if (parking === null || parking.Capacity === 0) { - capacity.unknown = true; + if (parking === null) { + capacity.unknown = true + } else if (parking.fietsenstalling_secties.length === 0) { + capacity.unknown = false; + capacity.total = parking.Capacity || 0; } else { // Get parking section (new: 1 per parking, to make it easy) parking.fietsenstalling_secties.forEach((sectie) => { @@ -41,7 +44,7 @@ const calculateCapacityData = (parking: ParkingDetailsType): capacitydata | null let detailed = capacity.detailed[name]; if (detailed !== undefined) { detailed.Toegestaan = detailed.Toegestaan || (data.Toegestaan !== null && data.Toegestaan); - detailed.Capaciteit += detailed.Capaciteit || 0; + detailed.Capaciteit += data.Capaciteit || 0; } // capacity.detailed[name].Toegestaan = capacity.detailed[name].Toegestaan || data.Toegestaan !== null && data.Toegestaan; // capacity.detailed[name].Capaciteit += data.Capaciteit || 0; @@ -63,9 +66,11 @@ const ParkingViewCapaciteit = ({ parkingdata }: { parkingdata: ParkingDetailsTyp const capacitydata = calculateCapacityData(parkingdata); // console.log("#### capacitydata", capacitydata, parkingdata); - if (capacitydata === null || capacitydata?.unknown) { - content = "Onbekend"; - } else if (capacitydata.detailed === null || Object.keys(capacitydata.detailed).length === 0) { + if (capacitydata === null || capacitydata?.unknown || (Object.keys(capacitydata.detailed).length === 0 && capacitydata.total === 0)) { + return null; + } + + if (capacitydata.detailed === null || Object.keys(capacitydata.detailed).length === 0) { content = ( <>
{parkingdata.Capacity}
@@ -98,6 +103,10 @@ const ParkingViewCapaciteit = ({ parkingdata }: { parkingdata: ParkingDetailsTyp }); } + if (content === null) { + return null; + } + return ( <> diff --git a/src/components/parking/ParkingViewServices.tsx b/src/components/parking/ParkingViewServices.tsx index 940d6a6..f4b6266 100644 --- a/src/components/parking/ParkingViewServices.tsx +++ b/src/components/parking/ParkingViewServices.tsx @@ -7,6 +7,8 @@ import { getAllServices } from "~/utils/parkings"; +export type ServiceType = { ID: string, Name: string }; + const ParkingViewServices = ({ parkingdata }: { parkingdata: any }) => { const [allServices, setAllServices] = React.useState([]); @@ -32,6 +34,12 @@ const ParkingViewServices = ({ parkingdata }: { parkingdata: any }) => { return null } + const activeServices = allServices && allServices.filter((service: any) => serviceIsActive(service)) || []; + if (activeServices.length === 0) { + // dont show services header if there are none + return null; + } + return <>
diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts index 0955a3e..67888f3 100644 --- a/src/pages/api/auth/[...nextauth].ts +++ b/src/pages/api/auth/[...nextauth].ts @@ -4,7 +4,7 @@ import type { Provider } from "next-auth/providers"; import NextAuth from "next-auth"; // import { PrismaAdapter } from "@auth/prisma-adapter" -import type { NextAuthOptions, User } from "next-auth"; +import type { NextAuthOptions, RequestInternal, User } from "next-auth"; // import EmailProvider from "next-auth/providers/email" import CredentialsProvider from "next-auth/providers/credentials"; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 11ba1cc..69f8e8b 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -56,7 +56,6 @@ export async function getServerSideProps(context: any) { const fietsenstallingen: fietsenstallingen[] = await getParkingsFromDatabase(sites); // TODO: Don't include: EditorCreated, EditorModified - console.log("###### sites", sites) return { props: { diff --git a/src/utils/parkings.tsx b/src/utils/parkings.tsx index 91d72e3..112d935 100644 --- a/src/utils/parkings.tsx +++ b/src/utils/parkings.tsx @@ -167,6 +167,30 @@ export const getDefaultLocation = (): string => { return '52.09066,5.121317' } +// const getNewStallingSectieDefaultRecord = () => { +// const sectieId = generateRandomId(); + +// return { +// sectieId, +// externalId: "", +// titel: "sectie 1", +// omschrijving: "", +// capaciteit: 0, +// CapaciteitBromfiets: 0, +// kleur: "00FF00", +// // fietsenstallingsId: null, +// isKluis: 0, +// reserveringskostenPerDag: null, +// urlwebservice: 0, +// Reservable: 0, +// NotaVerwijssysteem: null, +// Bezetting: 0, +// isactief: 1, +// qualificatie: "NONE", +// secties_fietstype: [] +// } +// } + export const getNewStallingDefaultRecord = (ID: string, latlong?: string[] | undefined): ParkingDetailsType => { const data: ParkingDetailsType = { ID, @@ -196,6 +220,8 @@ export const getNewStallingDefaultRecord = (ID: string, latlong?: string[] | und FMS: false, Beheerder: "", BeheerderContact: "", + + // fietsenstalling_secties: [getNewStallingSectieDefaultRecord()], } return data From 2e31172a2dd946d6b22a1dc35acc2c161f4c6d0e Mon Sep 17 00:00:00 2001 From: bartwr Date: Thu, 4 Apr 2024 09:44:26 +0200 Subject: [PATCH 4/4] Log in with credentials and not with magic email link --- src/pages/login.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 56f76d2..acc0da4 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -30,16 +30,16 @@ const Login: NextPage = () => { passwordRef.current && passwordRef.current.value !== '' ) { // console.log('signing in with magic link') - signIn("email", { - email: emailRef.current.value.trim(), - // password: passwordRef.current.value, - // callbackUrl: "/", - }); - // signIn("credentials", { + // signIn("email", { // email: emailRef.current.value.trim(), - // password: passwordRef.current.value, - // callbackUrl: "/", + // // password: passwordRef.current.value, + // // callbackUrl: "/", // }); + signIn("credentials", { + email: emailRef.current.value.trim(), + password: passwordRef.current.value, + callbackUrl: "/", + }); } else { alert('no email of password given'); }