From e9d14096c998c0f91538a2d582a4edb241c488d2 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 15 Jan 2025 17:10:49 -0500 Subject: [PATCH 01/35] disable volunteer routes --- apps/api/apps/catalog/routes/things.js | 72 +++++++++++++------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/apps/api/apps/catalog/routes/things.js b/apps/api/apps/catalog/routes/things.js index 2205691..3bb7ee6 100644 --- a/apps/api/apps/catalog/routes/things.js +++ b/apps/api/apps/catalog/routes/things.js @@ -3,8 +3,8 @@ const router = express.Router(); const { getCatalogData } = require('../services/catalog'); const { getThingDetails } = require('../services/thingDetails'); const { getItemDetails } = require('../services/itemDetails'); -const { enroll, getShifts } = require('../services/shifts'); -const { findMember } = require('../../../services/borrowers'); +// const { enroll, getShifts } = require('../services/shifts'); +// const { findMember } = require('../../../services/borrowers'); router.get('/', async (req, res) => { try { @@ -35,42 +35,42 @@ router.get('/items/:id', async (req, res) => { } }); -router.get('/volunteer/shifts', async (req, res) => { - const email = req.headers['x-email']; - try { - res.send(await getShifts({ email })); - } catch (error) { - console.error(error); - res.status(error.status || 500).send({ errors: [error] }); - } -}); +// router.get('/volunteer/shifts', async (req, res) => { +// const email = req.headers['x-email']; +// try { +// res.send(await getShifts({ email })); +// } catch (error) { +// console.error(error); +// res.status(error.status || 500).send({ errors: [error] }); +// } +// }); -router.post('/volunteer/auth', async (req, res) => { - const { email } = req.body; - try { - const member = await findMember({ email }); +// router.post('/volunteer/auth', async (req, res) => { +// const { email } = req.body; +// try { +// const member = await findMember({ email }); - if (member) { - res.send(member); - } else { - res.sendStatus(403); - } - } catch (error) { - console.error(error); - res.status(error.status || 500).send({ errors: [error] }); - } -}); +// if (member) { +// res.send(member); +// } else { +// res.sendStatus(403); +// } +// } catch (error) { +// console.error(error); +// res.status(error.status || 500).send({ errors: [error] }); +// } +// }); -router.post('/volunteer/shifts/enroll', async (req, res) => { - const email = req.headers['x-email']; - const { shifts } = req.body; - try { - await enroll(email, shifts); - res.sendStatus(204); - } catch (error) { - console.error(error); - res.status(error.status || 500).send({ errors: [error] }); - } -}); +// router.post('/volunteer/shifts/enroll', async (req, res) => { +// const email = req.headers['x-email']; +// const { shifts } = req.body; +// try { +// await enroll(email, shifts); +// res.sendStatus(204); +// } catch (error) { +// console.error(error); +// res.status(error.status || 500).send({ errors: [error] }); +// } +// }); module.exports = router; \ No newline at end of file From a7a6d58a6aa3bf379cb2d40265ee6204e5bbef56 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 15 Jan 2025 17:15:17 -0500 Subject: [PATCH 02/35] disable auth endpoint --- apps/api/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/api/server.js b/apps/api/server.js index 4123938..bf67c68 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -7,7 +7,7 @@ const buildDocOptions = require('./docs/scripts/buildOptions'); const swaggerUi = require('swagger-ui-express'); const app = express(); const bodyParser = require('body-parser'); -const auth = require('./auth'); +// const auth = require('./auth'); const things = require('./apps/catalog/routes/things'); const lending = require('./apps/librarian'); const cors = require('cors'); @@ -45,7 +45,7 @@ app.get('/', (_, res) => { app.use('/web', things); app.use('/things', things); app.use('/lending', lending); -app.use('/auth', auth); +// app.use('/auth', auth); const PORT = process.env.PORT || 8088; From 428c99befe5911464400aa6184ebab66ba563a4e Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 15 Jan 2025 20:00:37 -0500 Subject: [PATCH 03/35] add helment, remove x-powered-by header --- apps/api/package-lock.json | 13 +++++++++++-- apps/api/package.json | 1 + apps/api/server.js | 7 ++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/api/package-lock.json b/apps/api/package-lock.json index 1792b72..eb23f73 100644 --- a/apps/api/package-lock.json +++ b/apps/api/package-lock.json @@ -1,12 +1,12 @@ { "name": "pvdthings-api", - "version": "1.22.0", + "version": "1.22.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pvdthings-api", - "version": "1.22.0", + "version": "1.22.2", "license": "ISC", "dependencies": { "@supabase/supabase-js": "^2.45.4", @@ -15,6 +15,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.21.0", + "helmet": "^8.0.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0" }, @@ -2419,6 +2420,14 @@ "node": ">= 0.4" } }, + "node_modules/helmet": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.0.0.tgz", + "integrity": "sha512-VyusHLEIIO5mjQPUI1wpOAEu+wl6Q0998jzTxqUYGE45xCIcAxy3MsbEK/yyJUJ3ADeMoB6MornPH6GMWAf+Pw==", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", diff --git a/apps/api/package.json b/apps/api/package.json index 4477e5b..45fe7dc 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -24,6 +24,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.21.0", + "helmet": "^8.0.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0" }, diff --git a/apps/api/server.js b/apps/api/server.js index bf67c68..d698935 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -11,6 +11,7 @@ const bodyParser = require('body-parser'); const things = require('./apps/catalog/routes/things'); const lending = require('./apps/librarian'); const cors = require('cors'); +const helmet = require('helmet'); const apiKeyMiddleware = require('./middleware/apiKey'); const allowedOrigins = process.env.ACCESS_CONTROL_ALLOW_ORIGIN.split(','); @@ -36,12 +37,10 @@ const corsOptions = Object.freeze({ }); app.use(cors(corsOptions)); +app.use(helmet()); app.use(apiKeyMiddleware); app.use(bodyParser.json()); -app.get('/', (_, res) => { - res.send('You have reached the Things API'); -}); app.use('/web', things); app.use('/things', things); app.use('/lending', lending); @@ -60,6 +59,8 @@ if (isDevelopment()) { ); } +app.disable('x-powered-by'); + app.listen(PORT, () => { console.log(`PVD Things API listening on PORT ${PORT}...`); }); \ No newline at end of file From 04789b057f4ed3f7ab0fe5264999b96dc0073a71 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 15 Jan 2025 20:02:24 -0500 Subject: [PATCH 04/35] override default 404 response --- apps/api/server.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/api/server.js b/apps/api/server.js index d698935..5470eff 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -46,6 +46,10 @@ app.use('/things', things); app.use('/lending', lending); // app.use('/auth', auth); +app.use((req, res, next) => { + res.status(404).send(); +}); + const PORT = process.env.PORT || 8088; if (isDevelopment()) { From e30a40be52eb8a7e70c8e5f17a07f6025d4ca6d4 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Wed, 15 Jan 2025 21:06:42 -0500 Subject: [PATCH 05/35] root server adjustments --- apps/api/server.js | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/apps/api/server.js b/apps/api/server.js index 5470eff..3585fa4 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -2,12 +2,8 @@ require('dotenv').config(); const { isDevelopment } = require('./utils/environment'); const express = require('express'); -const swaggerJsDoc = require('swagger-jsdoc'); -const buildDocOptions = require('./docs/scripts/buildOptions'); -const swaggerUi = require('swagger-ui-express'); const app = express(); const bodyParser = require('body-parser'); -// const auth = require('./auth'); const things = require('./apps/catalog/routes/things'); const lending = require('./apps/librarian'); const cors = require('cors'); @@ -28,10 +24,11 @@ const corsOptions = Object.freeze({ ], credentials: true, origin: (origin, callback) => { - if (allowedOrigins.includes(origin) || !origin) { + if (allowedOrigins.includes(origin) || !origin || isDevelopment()) { callback(null, true); } else { - callback(new Error('Not allowed by CORS')); + console.log('origin', origin); + callback(new Error('CORS Error')); } } }); @@ -44,27 +41,14 @@ app.use(bodyParser.json()); app.use('/web', things); app.use('/things', things); app.use('/lending', lending); -// app.use('/auth', auth); app.use((req, res, next) => { res.status(404).send(); }); -const PORT = process.env.PORT || 8088; - -if (isDevelopment()) { - const docOptions = buildDocOptions({ port: PORT }); - const specs = swaggerJsDoc(docOptions); - - app.use( - '/docs', - swaggerUi.serve, - swaggerUi.setup(specs, { explorer: true }) - ); -} - app.disable('x-powered-by'); +const PORT = process.env.PORT || 8088; app.listen(PORT, () => { - console.log(`PVD Things API listening on PORT ${PORT}...`); + console.log(`Server is running on port ${PORT}...`); }); \ No newline at end of file From 675cb08ee138b668c61087665a4909c00a27178b Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 19:21:59 -0500 Subject: [PATCH 06/35] authorize supabase user in api --- apps/api/middleware/adminAuthorization.js | 2 +- apps/api/middleware/supabaseAuthentication.js | 36 +++++-------------- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/apps/api/middleware/adminAuthorization.js b/apps/api/middleware/adminAuthorization.js index a87922c..0b1b43d 100644 --- a/apps/api/middleware/adminAuthorization.js +++ b/apps/api/middleware/adminAuthorization.js @@ -2,7 +2,7 @@ const { isAdmin } = require('../services/auth'); const authorizeAdminUser = async (req, res, next) => { const adminWhitelist = process.env.ADMIN_WHITELIST; - const userEmail = res.locals.user?.email; + const userEmail = req.user?.email; if (adminWhitelist && (!userEmail || !isAdmin(userEmail))) { res.status(403).send({ error: 'Not authorized' }); diff --git a/apps/api/middleware/supabaseAuthentication.js b/apps/api/middleware/supabaseAuthentication.js index 11d8b93..090e976 100644 --- a/apps/api/middleware/supabaseAuthentication.js +++ b/apps/api/middleware/supabaseAuthentication.js @@ -1,40 +1,20 @@ const { createClient } = require('@supabase/supabase-js'); -const { isWhitelisted } = require('../services/auth'); -const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUB_ANON_KEY, { - auth: { - autoRefreshToken: false, // All my Supabase access is from server, so no need to refresh the token - detectSessionInUrl: false, // We are not using OAuth, so we don't need this. Also, we are manually "detecting" the session in the server-side code - persistSession: false, // All our access is from server, so no need to persist the session to browser's local storage - } -}); +const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUB_ANON_KEY); const authenticateToken = async (req, res, next) => { - const environment = process.env.NODE_ENV || 'development'; - - if (req.method === 'OPTIONS' || environment === 'development') { - next(); - return; - } - const accessToken = req.headers['supabase-access-token']; - const refreshToken = req.headers['supabase-refresh-token']; - await supabase.auth.setSession({ - refresh_token: refreshToken, - access_token: accessToken, - }); + const { data: { user }, error } = await supabase.auth.getUser(accessToken); - const session = await supabase.auth.getSession(); - const user = await supabase.auth.getUser(); - - if (session.data.session && isWhitelisted(user.data.user.email)) { - res.locals.user = user.data.user; - next(); - } else { - console.error(`Invalid Token:\t ${session.error || 'NO ENTRY'}`) + if (error || !user) { + console.error(`Invalid Token`); res.status(401).send(); + return; } + + req.user = user; + next(); } module.exports = authenticateToken; \ No newline at end of file From 395014ec8396a00c70d511d9545e7edf43f2d9ad Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 19:23:42 -0500 Subject: [PATCH 07/35] librarian: authenticate with username and password --- apps/librarian/lib/constants.dart | 26 +- apps/librarian/lib/core/api/api.dart | 4 +- apps/librarian/lib/core/api/dio_client.dart | 4 +- apps/librarian/lib/core/core.dart | 3 +- apps/librarian/lib/core/pick_file.dart | 4 +- apps/librarian/lib/core/supabase.dart | 18 + apps/librarian/lib/main.dart | 15 +- .../authentication/pages/signin_page.dart | 112 ++-- .../providers/auth_service_provider.dart | 31 +- .../lib/modules/splash/pages/splash_page.dart | 2 +- .../things/details/inventory_details.dart | 3 +- apps/librarian/pubspec.lock | 531 ++++++++++-------- apps/librarian/pubspec.yaml | 14 +- 13 files changed, 455 insertions(+), 312 deletions(-) create mode 100644 apps/librarian/lib/core/supabase.dart diff --git a/apps/librarian/lib/constants.dart b/apps/librarian/lib/constants.dart index 5848aec..a6f9792 100644 --- a/apps/librarian/lib/constants.dart +++ b/apps/librarian/lib/constants.dart @@ -1,10 +1,24 @@ -const String supabaseUrl = String.fromEnvironment('SUPABASE_URL'); +import 'package:flutter_dotenv/flutter_dotenv.dart'; -const String supabasePublicKey = String.fromEnvironment('SUPABASE_PUBLIC_KEY'); +Future loadEnvironmentVariables() async { + await dotenv.load(isOptional: true); +} -const String apiHost = String.fromEnvironment('API_HOST', - defaultValue: 'http://localhost:8088/lending'); +const supabaseUrlKey = 'SUPABASE_URL'; +const supabasePublicKeyKey = 'SUPABASE_PUBLIC_KEY'; +const apiHostKey = 'API_HOST'; +const apiKeyKey = 'API_KEY'; +const appUrlKey = 'APP_URL'; -const String apiKey = String.fromEnvironment('API_KEY'); +const String _supabaseUrl = String.fromEnvironment(supabaseUrlKey); +const String _supabasePublicKey = String.fromEnvironment(supabasePublicKeyKey); +const String _apiHost = String.fromEnvironment(apiHostKey); +const String _apiKey = String.fromEnvironment(apiKeyKey); +const String _appUrl = String.fromEnvironment(appUrlKey); -const String appUrl = String.fromEnvironment('APP_URL'); +String get supabaseUrl => dotenv.get(supabaseUrlKey, fallback: _supabaseUrl); +String get supabasePublicKey => + dotenv.get(supabasePublicKeyKey, fallback: _supabasePublicKey); +String get apiHost => dotenv.get(apiHostKey, fallback: _apiHost); +String get apiKey => dotenv.get(apiKeyKey, fallback: _apiKey); +String get appUrl => dotenv.get(appUrlKey, fallback: _appUrl); diff --git a/apps/librarian/lib/core/api/api.dart b/apps/librarian/lib/core/api/api.dart index b316c85..bcdd046 100644 --- a/apps/librarian/lib/core/api/api.dart +++ b/apps/librarian/lib/core/api/api.dart @@ -1,8 +1,8 @@ -library api; +library; import 'package:dio/dio.dart'; import 'package:librarian_app/constants.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; +import 'package:librarian_app/core/supabase.dart'; part 'borrowers.dart'; part 'dio_client.dart'; diff --git a/apps/librarian/lib/core/api/dio_client.dart b/apps/librarian/lib/core/api/dio_client.dart index 3720b5a..5a4e10f 100644 --- a/apps/librarian/lib/core/api/dio_client.dart +++ b/apps/librarian/lib/core/api/dio_client.dart @@ -2,10 +2,10 @@ part of 'api.dart'; class DioClient { static String get _accessToken => - Supabase.instance.client.auth.currentSession?.accessToken ?? ''; + supabase.auth.currentSession?.accessToken ?? ''; static String get _refreshToken => - Supabase.instance.client.auth.currentSession?.refreshToken ?? ''; + supabase.auth.currentSession?.refreshToken ?? ''; static BaseOptions get _options { return BaseOptions( diff --git a/apps/librarian/lib/core/core.dart b/apps/librarian/lib/core/core.dart index 6693d10..ed9c13b 100644 --- a/apps/librarian/lib/core/core.dart +++ b/apps/librarian/lib/core/core.dart @@ -1,7 +1,6 @@ -library core; +library; import 'package:flutter/foundation.dart'; -import 'package:file_picker/_internal/file_picker_web.dart'; import 'package:file_picker/file_picker.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; diff --git a/apps/librarian/lib/core/pick_file.dart b/apps/librarian/lib/core/pick_file.dart index f5a2f2c..e70ef3b 100644 --- a/apps/librarian/lib/core/pick_file.dart +++ b/apps/librarian/lib/core/pick_file.dart @@ -1,7 +1,7 @@ part of 'core.dart'; Future pickDocumentFile() async { - FilePickerResult? result = await FilePickerWeb.platform.pickFiles( + FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['pdf'], ); @@ -16,7 +16,7 @@ Future pickDocumentFile() async { Future pickImageFile() async { FilePickerResult? result = - await FilePickerWeb.platform.pickFiles(type: FileType.image); + await FilePicker.platform.pickFiles(type: FileType.image); return result == null ? null : FileData( diff --git a/apps/librarian/lib/core/supabase.dart b/apps/librarian/lib/core/supabase.dart new file mode 100644 index 0000000..549b66b --- /dev/null +++ b/apps/librarian/lib/core/supabase.dart @@ -0,0 +1,18 @@ +import 'package:librarian_app/constants.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; + +import 'core.dart'; +import 'services/image_service.dart'; + +final supabase = Supabase.instance.client; + +Future initializeSupabase() async { + await Supabase.initialize( + url: supabaseUrl, + anonKey: supabasePublicKey, + ); + + if (supabaseUrl.isNotEmpty) { + Library.logoUrl = ImageService().getPublicUrl('library', 'settings/logo'); + } +} diff --git a/apps/librarian/lib/main.dart b/apps/librarian/lib/main.dart index e993db7..c949d04 100644 --- a/apps/librarian/lib/main.dart +++ b/apps/librarian/lib/main.dart @@ -1,23 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart' as riverpod; import 'package:librarian_app/constants.dart'; -import 'package:librarian_app/core/core.dart'; +import 'package:librarian_app/core/supabase.dart'; import 'package:librarian_app/modules/splash/pages/splash_page.dart'; -import 'package:librarian_app/core/services/image_service.dart'; import 'package:librarian_app/theme/indigo_theme.dart'; -import 'package:supabase_flutter/supabase_flutter.dart' as supabase; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - - await supabase.Supabase.initialize( - url: supabaseUrl, - anonKey: supabasePublicKey, - ); - - if (supabaseUrl.isNotEmpty) { - Library.logoUrl = ImageService().getPublicUrl('library', 'settings/logo'); - } + await loadEnvironmentVariables(); + initializeSupabase(); runApp(const riverpod.ProviderScope( child: LibrarianApp(), diff --git a/apps/librarian/lib/modules/authentication/pages/signin_page.dart b/apps/librarian/lib/modules/authentication/pages/signin_page.dart index f191937..736cee8 100644 --- a/apps/librarian/lib/modules/authentication/pages/signin_page.dart +++ b/apps/librarian/lib/modules/authentication/pages/signin_page.dart @@ -5,14 +5,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:librarian_app/core/core.dart'; import 'package:librarian_app/modules/authentication/providers/signin_error_provider.dart'; -import 'package:librarian_app/modules/authentication/widgets/discord_button.dart'; import 'package:librarian_app/modules/authentication/providers/auth_service_provider.dart'; import 'package:librarian_app/dashboard/pages/dashboard_page.dart'; import 'package:librarian_app/widgets/fade_page_route.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; class SignInPage extends ConsumerWidget { - const SignInPage({super.key}); + SignInPage({super.key}); + + final _emailController = TextEditingController(); + final _passwordController = TextEditingController(); + + bool get _canSubmit => + _emailController.text.isNotEmpty && _passwordController.text.isNotEmpty; @override Widget build(BuildContext context, WidgetRef ref) { @@ -24,17 +29,13 @@ class SignInPage extends ConsumerWidget { } Future signIn() async { - if (kDebugMode) { - navigateToDashboard(); - return; - } - try { - await ref - .read(authServiceProvider) - .signIn(onSuccess: navigateToDashboard); + await ref.read(authServiceProvider).signIn( + email: _emailController.text, + password: _passwordController.text, + onSuccess: navigateToDashboard); } on AuthException catch (error) { - ref.read(signinErrorProvider.notifier).state = error.toString(); + ref.read(signinErrorProvider.notifier).state = error.message; } catch (error) { ref.read(signinErrorProvider.notifier).state = "An unexpected error occurred."; @@ -45,35 +46,72 @@ class SignInPage extends ConsumerWidget { final cardHeight = min(240, screenSize.height); final cardWidth = min(cardHeight, screenSize.width); - final card = Card( - child: Padding( - padding: const EdgeInsets.all(16), - child: SizedBox( - height: cardHeight, - width: cardWidth, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - const Spacer(), - _LogoImage(), - const Spacer(), - DiscordSigninButton(onPressed: signIn), - if (ref.watch(signinErrorProvider) != null) ...[ - const SizedBox(height: 16), - Text(ref.read(signinErrorProvider)!) - ], - const Spacer(), - ], - ), - ), - ), - ); - return Scaffold( body: Padding( padding: const EdgeInsets.all(16), - child: Center(child: card), + child: Center( + child: Card( + child: Container( + padding: const EdgeInsets.all(16), + width: cardWidth, + child: Form( + autovalidateMode: AutovalidateMode.onUserInteraction, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + _LogoImage(), + const SizedBox(height: 8.0), + TextFormField( + controller: _emailController, + decoration: const InputDecoration( + labelText: 'Email', + ), + keyboardType: TextInputType.emailAddress, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Email is required'; + } + + return null; + }, + ), + const SizedBox(height: 8.0), + TextFormField( + controller: _passwordController, + decoration: const InputDecoration( + labelText: 'Password', + ), + keyboardType: TextInputType.visiblePassword, + obscureText: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Password is required'; + } + + return null; + }, + ), + const SizedBox(height: 16.0), + ListenableBuilder( + listenable: Listenable.merge([ + _emailController, + _passwordController, + ]), + builder: (context, _) => FilledButton.icon( + onPressed: _canSubmit ? signIn : null, + label: const Text('Sign in'), + ), + ), + if (ref.watch(signinErrorProvider) != null) ...[ + const SizedBox(height: 16.0), + Text(ref.read(signinErrorProvider)!) + ], + ], + ), + ), + ), + )), ), ); } diff --git a/apps/librarian/lib/modules/authentication/providers/auth_service_provider.dart b/apps/librarian/lib/modules/authentication/providers/auth_service_provider.dart index 4b4293d..a619b6c 100644 --- a/apps/librarian/lib/modules/authentication/providers/auth_service_provider.dart +++ b/apps/librarian/lib/modules/authentication/providers/auth_service_provider.dart @@ -1,33 +1,30 @@ import 'package:flutter_riverpod/flutter_riverpod.dart' as rp; -import 'package:librarian_app/constants.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; - -import 'user_provider.dart'; +import 'package:librarian_app/core/supabase.dart'; class AuthService { const AuthService(this.ref); final rp.Ref ref; - static SupabaseClient get _supabase => Supabase.instance.client; - - bool get hasValidSession => _supabase.auth.currentSession != null; + bool get hasValidSession => supabase.auth.currentSession != null; - Future signIn({void Function()? onSuccess}) async { - await _supabase.auth.signInWithOAuth(Provider.discord, - redirectTo: appUrl.isNotEmpty ? appUrl : null); + Future signIn({ + required String email, + required String password, + void Function()? onSuccess, + }) async { + await supabase.auth.signInWithPassword( + email: email, + password: password, + ); - if (onSuccess != null) { - ref.listen(userProvider, (_, user) { - if (user != null) { - onSuccess(); - } - }); + if (supabase.auth.currentUser != null) { + onSuccess?.call(); } } Future signOut() async { - await _supabase.auth.signOut(); + await supabase.auth.signOut(); } } diff --git a/apps/librarian/lib/modules/splash/pages/splash_page.dart b/apps/librarian/lib/modules/splash/pages/splash_page.dart index aec3119..2357403 100644 --- a/apps/librarian/lib/modules/splash/pages/splash_page.dart +++ b/apps/librarian/lib/modules/splash/pages/splash_page.dart @@ -23,7 +23,7 @@ class _SplashPageState extends ConsumerState { if (!service.hasValidSession) { Navigator.of(context).pushAndRemoveUntil( - createFadePageRoute(child: const SignInPage()), + createFadePageRoute(child: SignInPage()), (route) => false, ); } else { diff --git a/apps/librarian/lib/modules/things/details/inventory_details.dart b/apps/librarian/lib/modules/things/details/inventory_details.dart index 657b88c..e92709a 100644 --- a/apps/librarian/lib/modules/things/details/inventory_details.dart +++ b/apps/librarian/lib/modules/things/details/inventory_details.dart @@ -1,4 +1,3 @@ -import 'package:file_picker/_internal/file_picker_web.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -51,7 +50,7 @@ class InventoryDetails extends ConsumerWidget { const UpdatedImageModel(type: null, bytes: null); }, onReplace: () async { - FilePickerResult? result = await FilePickerWeb.platform + FilePickerResult? result = await FilePicker.platform .pickFiles(type: FileType.image); if (result != null) { ref.read(imageUploadProvider.notifier).state = diff --git a/apps/librarian/pubspec.lock b/apps/librarian/pubspec.lock index 14850eb..2d94105 100644 --- a/apps/librarian/pubspec.lock +++ b/apps/librarian/pubspec.lock @@ -5,42 +5,71 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: "88399e291da5f7e889359681a8f64b18c5123e03576b01f32a6a276611e511c3" url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "78.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: "62899ef43d0b962b056ed2ebac6b47ec76ffd003d5f7c4e4dc870afe63188e33" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "7.1.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916" url: "https://pub.dev" source: hosted - version: "0.11.3" + version: "0.12.0" app_links: dependency: transitive description: name: app_links - sha256: "3ced568a5d9e309e99af71285666f1f3117bddd0bd5b3317979dccc1a40cada4" + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" async: dependency: transitive description: @@ -61,50 +90,50 @@ packages: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.0.3" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.3" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "1414d6d733a85d8ad2f1dfcb3ea7945759e35a123cb99ccfac75d0758f75edfa" + sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.4.14" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "8.0.0" built_collection: dependency: transitive description: @@ -117,10 +146,10 @@ packages: dependency: transitive description: name: built_value - sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2" url: "https://pub.dev" source: hosted - version: "8.9.2" + version: "8.9.3" characters: dependency: transitive description: @@ -149,10 +178,10 @@ packages: dependency: transitive description: name: cli_util - sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "0.4.2" clock: dependency: transitive description: @@ -165,34 +194,42 @@ packages: dependency: transitive description: name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.10.1" collection: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" convert: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cupertino_icons: dependency: "direct main" description: @@ -205,34 +242,50 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "22bd87a362f433ba6aae127a7bac2838645270737f3721b180916d7c5946cb5d" + sha256: "6d509673c4dd0baa90e60dc8366bc2acc6690f16a7d44bfae31294d82c5d2a62" url: "https://pub.dev" source: hosted - version: "0.5.11" + version: "0.7.1" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: a85e8f78f4c52f6c63cdaf8c872eb573db0231dcdf3c3a5906d493c1f8bc20e6 + sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e" + url: "https://pub.dev" + source: hosted + version: "0.7.1" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: "14df0760dfa81b7b0c398c876045f4e4a343eb2c9d200c66163671dd3e337c1b" url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "1.0.0+7.1.0" dart_style: dependency: transitive description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "3.0.1" dio: dependency: "direct main" description: name: dio - sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" url: "https://pub.dev" source: hosted - version: "5.4.3+1" + version: "2.0.0" fake_async: dependency: transitive description: @@ -245,63 +298,71 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_picker: dependency: "direct main" description: name: file_picker - sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" + sha256: c904b4ab56d53385563c7c39d8e9fa9af086f91495dfc48717ad84a42c3cf204 url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "8.1.7" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b + url: "https://pub.dev" + source: hosted + version: "5.2.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" + sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" url: "https://pub.dev" source: hosted - version: "2.0.19" + version: "2.0.24" flutter_riverpod: dependency: "direct main" description: name: flutter_riverpod - sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.1" flutter_test: dependency: "direct dev" description: flutter @@ -316,10 +377,10 @@ packages: dependency: transitive description: name: freezed_annotation - sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.4" frontend_server_client: dependency: transitive description: @@ -332,10 +393,10 @@ packages: dependency: transitive description: name: functions_client - sha256: "3b157b4d3ae9e38614fd80fab76d1ef1e0e39ff3412a45de2651f27cecb9d2d2" + sha256: "61597ed93be197b1be6387855e4b760e6aac2355fcfc4df6d20d2b4579982158" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "2.4.0" glob: dependency: transitive description: @@ -348,18 +409,18 @@ packages: dependency: transitive description: name: gotrue - sha256: f3a47cdbc59e543f453a1ef150050cd7650fe756254ac1fcac1d2a2f6f2b5a21 + sha256: d6362dff9a54f8c1c372bb137c858b4024c16407324d34e6473e59623c9b9f50 url: "https://pub.dev" source: hosted - version: "1.12.6" + version: "2.11.1" graphs: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" gtk: dependency: transitive description: @@ -368,62 +429,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" - hive: - dependency: transitive - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - hive_flutter: - dependency: transitive - description: - name: hive_flutter - sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc - url: "https://pub.dev" - source: hosted - version: "1.1.0" http: dependency: transitive description: name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.13.6" + version: "1.2.2" http_multi_server: dependency: transitive description: name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" intl: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: "00f33b908655e606b86d2ade4710a231b802eec6f11e87e4ea3783fd72077a50" url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.20.1" io: dependency: transitive description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" js: dependency: transitive description: @@ -452,18 +497,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -476,18 +521,26 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.1.1" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "0.1.3-main.0" matcher: dependency: transitive description: @@ -516,18 +569,18 @@ packages: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "2.0.0" package_config: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" path: dependency: transitive description: @@ -540,26 +593,26 @@ packages: dependency: transitive description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -580,26 +633,26 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" phone_numbers_parser: dependency: "direct main" description: name: phone_numbers_parser - sha256: "75986ce6185a601afcb791f79a650bbcb438c5672482da7efa40f0002a57cc74" + sha256: "8aaa49708c9314d450d80767753c6512402e848138e5a91bf59ed3e0d3ac5d9b" url: "https://pub.dev" source: hosted - version: "9.0.2" + version: "9.0.3" platform: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -620,34 +673,34 @@ packages: dependency: transitive description: name: postgrest - sha256: f190eddc5779842dfa529fa239ec4b1025f6f968c18052ba6fffc0aecac93e6b + sha256: b74dc0f57b5dca5ce9f57a54b08110bf41d6fc8a0483c0fec10c79e9aa0fb2bb url: "https://pub.dev" source: hosted - version: "1.5.2" + version: "2.4.1" pub_semver: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.5.0" realtime_client: dependency: transitive description: name: realtime_client - sha256: "2027358cdbe65d5f1770c3f768aa9adecd394de486c5dbbd2cfe19d5c6dbbc4a" + sha256: "1bfcb7455fdcf15953bf18ac2817634ea5b8f7f350c7e8c9873141a3ee2c3e9c" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "2.4.1" retry: dependency: transitive description: @@ -660,79 +713,135 @@ packages: dependency: transitive description: name: riverpod - sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.1" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "8b71f03fc47ae27d13769496a1746332df4cec43918aeba9aff1e232783a780f" + sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.9" riverpod_annotation: dependency: "direct main" description: name: riverpod_annotation - sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c + sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.6.1" riverpod_generator: dependency: "direct dev" description: name: riverpod_generator - sha256: d451608bf17a372025fc36058863737636625dfdb7e3cbf6142e0dfeb366ab22 + sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.4" rxdart: dependency: transitive description: name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84 + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "0.27.7" + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" skeletonizer: dependency: "direct main" description: name: skeletonizer - sha256: "3b202e4fa9c49b017d368fb0e570d4952bcd19972b67b2face071bdd68abbfae" + sha256: "0dcacc51c144af4edaf37672072156f49e47036becbc394d7c51850c5c1e884b" url: "https://pub.dev" source: hosted - version: "1.4.2" + version: "1.4.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_gen: dependency: transitive description: name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "2.0.0" source_span: dependency: transitive description: @@ -753,10 +862,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" state_notifier: dependency: transitive description: @@ -769,10 +878,10 @@ packages: dependency: transitive description: name: storage_client - sha256: f02d4d8967bec77767dcaf9daf24ca5b8d5a9f1cc093f14dffb77930b52589a3 + sha256: d80d34f0aa60e5199646bc301f5750767ee37310c2ecfe8d4bbdd29351e09ab0 url: "https://pub.dev" source: hosted - version: "1.5.4" + version: "2.3.0" stream_channel: dependency: transitive description: @@ -785,34 +894,34 @@ packages: dependency: transitive description: name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" supabase: dependency: transitive description: name: supabase - sha256: "1434bb9375f88f51802dadf7b99568117c434f6a9af7f8a55e5be94c8b4da7c9" + sha256: "270f63cd87a16578fee87e40cbf61062e8cdbce68d5e723e665f4651d70ddd8c" url: "https://pub.dev" source: hosted - version: "1.11.11" + version: "2.6.2" supabase_flutter: dependency: "direct main" description: name: supabase_flutter - sha256: "2cc98ff2a6aa4ad2ab9f263428eda998886cb70ed24695f106aa25c02ecba854" + sha256: ca8dfe3d4b109e7338cdf7778f3ec2c660a0178006876bfac343eb39b0f3d1e3 url: "https://pub.dev" source: hosted - version: "1.6.2" + version: "2.8.3" term_glyph: dependency: transitive description: @@ -825,66 +934,66 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" timing: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.2.6" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "17cd5e205ea615e2c6ea7a77323a11712dffa0720a8a90540db57a01347f9ad9" + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89" + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -897,26 +1006,26 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" + sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.4" uuid: dependency: "direct main" description: name: uuid - sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.1" vector_math: dependency: transitive description: @@ -929,98 +1038,74 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" watcher: dependency: transitive description: name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" web: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.5.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" - url: "https://pub.dev" - source: hosted - version: "2.4.5" - webview_flutter: - dependency: transitive - description: - name: webview_flutter - sha256: "392c1d83b70fe2495de3ea2c84531268d5b8de2de3f01086a53334d8b6030a88" - url: "https://pub.dev" - source: hosted - version: "3.0.4" - webview_flutter_android: - dependency: transitive - description: - name: webview_flutter_android - sha256: "8b3b2450e98876c70bfcead876d9390573b34b9418c19e28168b74f6cb252dbd" - url: "https://pub.dev" - source: hosted - version: "2.10.4" - webview_flutter_platform_interface: + version: "1.1.0" + web_socket: dependency: transitive description: - name: webview_flutter_platform_interface - sha256: "812165e4e34ca677bdfbfa58c01e33b27fd03ab5fa75b70832d4b7d4ca1fa8cf" + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" url: "https://pub.dev" source: hosted - version: "1.9.5" - webview_flutter_wkwebview: + version: "0.1.6" + web_socket_channel: dependency: transitive description: - name: webview_flutter_wkwebview - sha256: a5364369c758892aa487cbf59ea41d9edd10f9d9baf06a94e80f1bd1b4c7bbc0 + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.9.5" + version: "3.0.1" win32: dependency: transitive description: name: win32 - sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 + sha256: "154360849a56b7b67331c21f09a386562d88903f90a1099c5987afc1912e1f29" url: "https://pub.dev" source: hosted - version: "5.5.1" + version: "5.10.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" yaml: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" yet_another_json_isolate: dependency: transitive description: name: yet_another_json_isolate - sha256: "86fad76026c4241a32831d6c7febd8f9bded5019e2cd36c5b148499808d8307d" + sha256: "56155e9e0002cc51ea7112857bbcdc714d4c35e176d43e4d3ee233009ff410c9" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "2.0.3" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.6.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/apps/librarian/pubspec.yaml b/apps/librarian/pubspec.yaml index 93e36e2..4daf301 100644 --- a/apps/librarian/pubspec.yaml +++ b/apps/librarian/pubspec.yaml @@ -10,7 +10,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. -version: 1.0.0+26 +version: 1.0.0+27 environment: sdk: '>=3.0.0' @@ -29,10 +29,10 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - supabase_flutter: ^1.5.0 + supabase_flutter: ^2.8.3 dio: ^5.0.3 - intl: ^0.18.0 - file_picker: ^6.0.0 + intl: ^0.20.1 + file_picker: ^8.1.7 uuid: ^4.1.0 flutter_riverpod: ^2.4.1 riverpod_annotation: ^2.1.6 @@ -40,6 +40,7 @@ dependencies: url_launcher: ^6.2.5 skeletonizer: ^1.4.2 phone_numbers_parser: ^9.0.2 + flutter_dotenv: ^5.2.1 dev_dependencies: flutter_test: @@ -50,10 +51,10 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^3.0.0 + flutter_lints: ^5.0.0 riverpod_generator: ^2.3.3 build_runner: ^2.4.6 - custom_lint: ^0.5.3 + custom_lint: ^0.7.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -69,6 +70,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - web/assets/ + - .env # An image asset can refer to one or more resolution-specific "variants", see From 4df33da4d3528a03b5c4b9f6e4b479ac0fc68e3e Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 19:31:02 -0500 Subject: [PATCH 08/35] rename access token headers --- apps/api/middleware/supabaseAuthentication.js | 2 +- apps/api/server.js | 4 ++-- apps/librarian/lib/core/api/dio_client.dart | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/api/middleware/supabaseAuthentication.js b/apps/api/middleware/supabaseAuthentication.js index 090e976..ca67bd3 100644 --- a/apps/api/middleware/supabaseAuthentication.js +++ b/apps/api/middleware/supabaseAuthentication.js @@ -3,7 +3,7 @@ const { createClient } = require('@supabase/supabase-js'); const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUB_ANON_KEY); const authenticateToken = async (req, res, next) => { - const accessToken = req.headers['supabase-access-token']; + const accessToken = req.headers['x-access-token']; const { data: { user }, error } = await supabase.auth.getUser(accessToken); diff --git a/apps/api/server.js b/apps/api/server.js index 3585fa4..7eabfee 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -19,8 +19,8 @@ const corsOptions = Object.freeze({ 'X-Requested-With', 'Content-Type', 'Accept', - 'supabase-access-token', - 'supabase-refresh-token' + 'x-access-token', + 'x-refresh-token' ], credentials: true, origin: (origin, callback) => { diff --git a/apps/librarian/lib/core/api/dio_client.dart b/apps/librarian/lib/core/api/dio_client.dart index 5a4e10f..0d301b6 100644 --- a/apps/librarian/lib/core/api/dio_client.dart +++ b/apps/librarian/lib/core/api/dio_client.dart @@ -13,8 +13,8 @@ class DioClient { contentType: 'application/json', headers: { 'x-api-key': apiKey, - 'supabase-access-token': _accessToken, - 'supabase-refresh-token': _refreshToken, + 'x-access-token': _accessToken, + 'x-refresh-token': _refreshToken, }, ); } From 02763c1e4d7b32fa2a3bc2ec97684d11e34a3148 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 21:16:29 -0500 Subject: [PATCH 09/35] remove swagger --- apps/api/docs/auth/paths/check.yaml | 9 -- apps/api/docs/catalog/paths/things.yaml | 20 ----- apps/api/docs/catalog/schemas/thing.yaml | 39 -------- apps/api/docs/librarian/paths/borrowers.yaml | 38 -------- apps/api/docs/librarian/paths/inventory.yaml | 57 ------------ apps/api/docs/librarian/paths/loans.yaml | 74 ---------------- apps/api/docs/librarian/paths/messages.yaml | 14 --- apps/api/docs/librarian/paths/payments.yaml | 28 ------ apps/api/docs/librarian/paths/things.yaml | 88 ------------------- apps/api/docs/librarian/schemas/borrower.yaml | 29 ------ .../docs/librarian/schemas/detailed_loan.yaml | 38 -------- .../librarian/schemas/detailed_thing.yaml | 47 ---------- apps/api/docs/librarian/schemas/item.yaml | 56 ------------ apps/api/docs/librarian/schemas/loan.yaml | 32 ------- apps/api/docs/librarian/schemas/payment.yaml | 18 ---- apps/api/docs/librarian/schemas/thing.yaml | 45 ---------- apps/api/docs/scripts/buildOptions.js | 26 ------ apps/api/docs/shared/headers.yaml | 18 ---- apps/api/package.json | 6 +- 19 files changed, 2 insertions(+), 680 deletions(-) delete mode 100644 apps/api/docs/auth/paths/check.yaml delete mode 100644 apps/api/docs/catalog/paths/things.yaml delete mode 100644 apps/api/docs/catalog/schemas/thing.yaml delete mode 100644 apps/api/docs/librarian/paths/borrowers.yaml delete mode 100644 apps/api/docs/librarian/paths/inventory.yaml delete mode 100644 apps/api/docs/librarian/paths/loans.yaml delete mode 100644 apps/api/docs/librarian/paths/messages.yaml delete mode 100644 apps/api/docs/librarian/paths/payments.yaml delete mode 100644 apps/api/docs/librarian/paths/things.yaml delete mode 100644 apps/api/docs/librarian/schemas/borrower.yaml delete mode 100644 apps/api/docs/librarian/schemas/detailed_loan.yaml delete mode 100644 apps/api/docs/librarian/schemas/detailed_thing.yaml delete mode 100644 apps/api/docs/librarian/schemas/item.yaml delete mode 100644 apps/api/docs/librarian/schemas/loan.yaml delete mode 100644 apps/api/docs/librarian/schemas/payment.yaml delete mode 100644 apps/api/docs/librarian/schemas/thing.yaml delete mode 100644 apps/api/docs/scripts/buildOptions.js delete mode 100644 apps/api/docs/shared/headers.yaml diff --git a/apps/api/docs/auth/paths/check.yaml b/apps/api/docs/auth/paths/check.yaml deleted file mode 100644 index 9280ae9..0000000 --- a/apps/api/docs/auth/paths/check.yaml +++ /dev/null @@ -1,9 +0,0 @@ -paths: - /auth/check: - post: - summary: Checks whether a given email is whitelisted for logon - responses: - '200': - description: Whitelisted - '401': - description: Not whitelisted \ No newline at end of file diff --git a/apps/api/docs/catalog/paths/things.yaml b/apps/api/docs/catalog/paths/things.yaml deleted file mode 100644 index 1c61228..0000000 --- a/apps/api/docs/catalog/paths/things.yaml +++ /dev/null @@ -1,20 +0,0 @@ -paths: - /things: - get: - summary: Fetches the data for the catalog app, including things and categories - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - things: - type: array - items: - $ref: '#/components/schemas/Catalog Thing' - categories: - type: array - items: - type: string \ No newline at end of file diff --git a/apps/api/docs/catalog/schemas/thing.yaml b/apps/api/docs/catalog/schemas/thing.yaml deleted file mode 100644 index 5e12f61..0000000 --- a/apps/api/docs/catalog/schemas/thing.yaml +++ /dev/null @@ -1,39 +0,0 @@ -components: - schemas: - Catalog Thing: - type: object - required: - - id - - name - properties: - id: - type: string - description: The auto-generated id of the thing - name: - type: string - description: The name of the thing - spanishName: - type: string - description: The Spanish translation of the name - categories: - type: array - items: - type: string - description: The categories of this thing belongs to - image: - type: string - format: url - description: A URL pointing to the image of the thing - stock: - type: number - description: The total number of this thing in stock - available: - type: number - description: The number of this thing available to borrow - example: - id: rec12345 - name: Hammer - spanishName: Martillo - categories: [DIY] - stock: 5 - available: 3 \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/borrowers.yaml b/apps/api/docs/librarian/paths/borrowers.yaml deleted file mode 100644 index 2ed3da8..0000000 --- a/apps/api/docs/librarian/paths/borrowers.yaml +++ /dev/null @@ -1,38 +0,0 @@ -paths: - /lending/borrowers: - get: - summary: Gets an array of all borrowers - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Borrower' - /lending/borrowers/{id}: - get: - summary: Gets a borrower from its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Borrower' - /lending/borrowers/{id}/contact: - patch: - summary: Updates a borrower's contact details from its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Updates applied \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/inventory.yaml b/apps/api/docs/librarian/paths/inventory.yaml deleted file mode 100644 index 1308bce..0000000 --- a/apps/api/docs/librarian/paths/inventory.yaml +++ /dev/null @@ -1,57 +0,0 @@ -paths: - /lending/inventory: - get: - summary: Gets an array of all items - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Item' - put: - summary: Creates new items - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: Items created - /lending/inventory/{number}: - get: - summary: Gets an item from its unique lending number - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Item' - '404': - description: Item not found - /lending/inventory/{id}: - patch: - summary: Updates an item from its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Item updated - /lending/inventory/{id}/convert: - post: - summary: Converts an item into a different type of thing - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Item converted \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/loans.yaml b/apps/api/docs/librarian/paths/loans.yaml deleted file mode 100644 index d10bde7..0000000 --- a/apps/api/docs/librarian/paths/loans.yaml +++ /dev/null @@ -1,74 +0,0 @@ -paths: - /lending/loans: - get: - summary: Gets an array of all loans - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Loan' - put: - summary: Creates new loans - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '201': - description: Loans created - /lending/loans/{loanId}/{thingId}: - get: - summary: Gets a loan by its unique id and the thing's unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Detailed Loan' - '404': - description: Loan not found - patch: - summary: Updates a loan by its unique id and the thing's unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Loan updated - /lending/loans/extend: - head: - summary: Determines whether the authenticated user is authorized to use this endpoint - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Authorized - '403': - description: Not Authorized - post: - summary: Changes all active loan due dates - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - description: True if the action ran successfully \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/messages.yaml b/apps/api/docs/librarian/paths/messages.yaml deleted file mode 100644 index 1d6e1c2..0000000 --- a/apps/api/docs/librarian/paths/messages.yaml +++ /dev/null @@ -1,14 +0,0 @@ -paths: - /lending/messages/loan-reminder: - post: - summary: Sends a loan reminder message, given the loan number - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Message sent - content: - application/json: - schema: - type: object \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/payments.yaml b/apps/api/docs/librarian/paths/payments.yaml deleted file mode 100644 index 35dc0c2..0000000 --- a/apps/api/docs/librarian/paths/payments.yaml +++ /dev/null @@ -1,28 +0,0 @@ -paths: - /lending/payments/{borrowerId}: - get: - summary: Fetches an array of payments for a borrower, given its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: Payments fetched - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Payment' - put: - summary: Posts a cash payment for a borrower, given its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '201': - description: Payment posted - content: - application/json: - schema: - type: object \ No newline at end of file diff --git a/apps/api/docs/librarian/paths/things.yaml b/apps/api/docs/librarian/paths/things.yaml deleted file mode 100644 index 5ad3e88..0000000 --- a/apps/api/docs/librarian/paths/things.yaml +++ /dev/null @@ -1,88 +0,0 @@ -paths: - /lending/things/categories: - get: - summary: Gets an array of possible thing categories - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - type: string - /lending/things: - get: - summary: Gets an array of all things - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Thing' - put: - summary: Creates a new thing - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: Thing created - /lending/things/{id}: - get: - summary: Gets a thing by its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Detailed Thing' - '404': - description: Thing not found - patch: - summary: Updates a thing by its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Thing updated - delete: - summary: Deletes a thing by its unique id - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Thing deleted - /lending/things/{id}/categories: - patch: - summary: Updates the categories of a thing - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '204': - description: Thing categories updated - /lending/things/{id}/image: - delete: - summary: Deletes the image of a thing - parameters: - - $ref: '#/components/parameters/SupabaseAccessToken' - - $ref: '#/components/parameters/SupabaseRefreshToken' - responses: - '200': - description: Thing image deleted \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/borrower.yaml b/apps/api/docs/librarian/schemas/borrower.yaml deleted file mode 100644 index 59fdecc..0000000 --- a/apps/api/docs/librarian/schemas/borrower.yaml +++ /dev/null @@ -1,29 +0,0 @@ -components: - schemas: - Borrower: - type: object - required: - - id - - name - - contact - - issues - properties: - id: - type: string - description: The auto-generated id of the borrower - name: - type: string - description: The full name of the borrower - contact: - type: object - description: The phone and email contact details of the borrower - issues: - type: array - items: - type: string - description: Outstanding issues related to the borrower's membership - example: - id: rec12345 - name: Jane Doe - contact: { "phone": "4015555555", "email": "jane@mail.com" } - issues: ["duesNotPaid"] \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/detailed_loan.yaml b/apps/api/docs/librarian/schemas/detailed_loan.yaml deleted file mode 100644 index d650deb..0000000 --- a/apps/api/docs/librarian/schemas/detailed_loan.yaml +++ /dev/null @@ -1,38 +0,0 @@ -components: - schemas: - Detailed Loan: - type: object - required: - - id - - thing - - borrower - - checkedOutDate - - dueDate - properties: - id: - type: string - description: The auto-generated id of the loan - thing: - $ref: '#/components/schemas/Thing' - description: An object containing the id, name, and number of the lent thing - borrower: - $ref: '#/components/schemas/Borrower' - description: A Borrower object - checkedOutDate: - type: string - format: timestamp - description: The date of when the thing was checked out - checkedInDate: - type: string - format: timestamp - description: The date of when the thing was checked back in - dueDate: - type: string - format: timestamp - description: The date of when the thing is due back - notes: - type: string - description: Notes attached to the loan - remindersSent: - type: number - description: The number of reminder emails sent to the borrower \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/detailed_thing.yaml b/apps/api/docs/librarian/schemas/detailed_thing.yaml deleted file mode 100644 index a021ca7..0000000 --- a/apps/api/docs/librarian/schemas/detailed_thing.yaml +++ /dev/null @@ -1,47 +0,0 @@ -components: - schemas: - Detailed Thing: - type: object - required: - - id - - name - - hidden - - stock - - available - - categories - - images - - items - properties: - id: - type: string - description: The auto-generated id of the thing - name: - type: string - description: The name of the thing - name_es: - type: string - description: The Spanish translation of the name - hidden: - type: boolean - description: Whether the thing is not allowed for lending - stock: - type: number - description: The total number of this thing in stock - available: - type: number - description: The number of this thing available to borrow - categories: - type: array - items: - type: string - description: The categories of this thing belongs to - images: - type: array - items: - type: string - description: URLs pointing to images of this thing - items: - type: array - items: - $ref: '#/components/schemas/Item' - description: Inventory items that belong to this class of thing \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/item.yaml b/apps/api/docs/librarian/schemas/item.yaml deleted file mode 100644 index 854b541..0000000 --- a/apps/api/docs/librarian/schemas/item.yaml +++ /dev/null @@ -1,56 +0,0 @@ -components: - schemas: - Item: - type: object - required: - - id - - number - - name - - hidden - - available - - totalLoans - - images - properties: - id: - type: string - description: The auto-generated id of the item - name: - type: string - description: The name of the thing associated with this item - number: - type: integer - description: The auto-generated number of this item, used for lending - brand: - type: string - description: The manufacturer or brand name of this item - description: - type: string - description: The description of this item - condition: - type: string - description: The condition of the item - estimatedValue: - type: number - description: The estimated value of the item (in dollars) - hidden: - type: boolean - description: Whether this item is not allowed for lending - eyeProtection: - type: boolean - description: Whether eye protection is required for lending - available: - type: boolean - description: False if this item is currently checked out - totalLoans: - type: number - description: The total number of times this item has been borrowed - images: - type: array - items: - type: string - description: URLs pointing to images of this item - manuals: - type: array - items: - type: object - description: Manual objects with URLs and filenames \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/loan.yaml b/apps/api/docs/librarian/schemas/loan.yaml deleted file mode 100644 index 87967fa..0000000 --- a/apps/api/docs/librarian/schemas/loan.yaml +++ /dev/null @@ -1,32 +0,0 @@ -components: - schemas: - Loan: - type: object - required: - - id - - thing - - borrower - - checkedOutDate - - dueDate - properties: - id: - type: string - description: The auto-generated id of the loan - thing: - $ref: '#/components/schemas/Thing' - description: An object containing the id, name, and number of the lent thing - borrower: - $ref: '#/components/schemas/Borrower' - description: A Borrower object - checkedOutDate: - type: string - format: timestamp - description: The date of when the thing was checked out - checkedInDate: - type: string - format: timestamp - description: The date of when the thing was checked back in - dueDate: - type: string - format: timestamp - description: The date of when the thing is due back \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/payment.yaml b/apps/api/docs/librarian/schemas/payment.yaml deleted file mode 100644 index fbe9451..0000000 --- a/apps/api/docs/librarian/schemas/payment.yaml +++ /dev/null @@ -1,18 +0,0 @@ -components: - schemas: - Payment: - type: object - required: - - id - - cash - - date - properties: - id: - type: string - description: The auto-generated id of the payment - cash: - type: number - description: The payment amount, in US Dollars - date: - type: string - description: The timestamp of the payment \ No newline at end of file diff --git a/apps/api/docs/librarian/schemas/thing.yaml b/apps/api/docs/librarian/schemas/thing.yaml deleted file mode 100644 index cced3aa..0000000 --- a/apps/api/docs/librarian/schemas/thing.yaml +++ /dev/null @@ -1,45 +0,0 @@ -components: - schemas: - Thing: - type: object - required: - - id - - name - - hidden - - stock - - available - - images - properties: - id: - type: string - description: The auto-generated id of the thing - name: - type: string - description: The name of the thing - name_es: - type: string - description: The Spanish translation of the name - hidden: - type: boolean - description: Whether the thing is not allowed for lending - eyeProtection: - type: boolean - description: Whether eye protection is required for lending - stock: - type: number - description: The total number of this thing in stock - available: - type: number - description: The number of this thing available to borrow - images: - type: array - items: - type: string - description: URLs pointing to images of this thing - example: - id: rec12345 - name: Hammer - name_es: Martillo - hidden: false - stock: 5 - available: 3 \ No newline at end of file diff --git a/apps/api/docs/scripts/buildOptions.js b/apps/api/docs/scripts/buildOptions.js deleted file mode 100644 index 3a2a25b..0000000 --- a/apps/api/docs/scripts/buildOptions.js +++ /dev/null @@ -1,26 +0,0 @@ -const options = { - definition: { - openapi: "3.1.0", - info: { - title: "PVD Things API", - version: "1.0.0", - description: - "A bridge between Airtable, Supabase, and the PVD Things suite of applications.", - license: { - name: "GNU General Public License v3.0", - url: "https://www.gnu.org/licenses/gpl-3.0.en.html", - }, - }, - servers: [], - }, - apis: ["./docs/**/*.yaml"], -}; - -const buildOptions = ({ port }) => { - let builtOptions = options; - builtOptions.servers = [{ url: `http://localhost/${port}` }]; - - return builtOptions; -}; - -module.exports = buildOptions; \ No newline at end of file diff --git a/apps/api/docs/shared/headers.yaml b/apps/api/docs/shared/headers.yaml deleted file mode 100644 index fa7d342..0000000 --- a/apps/api/docs/shared/headers.yaml +++ /dev/null @@ -1,18 +0,0 @@ -components: - parameters: - SupabaseAccessToken: - in: header - name: supabase-access-token - description: An access token generated by Supabase SSO - schema: - type: string - format: jwt - required: true - SupabaseRefreshToken: - in: header - name: supabase-refresh-token - description: A refresh token generated by Supabase SSO - schema: - type: string - format: jwt - required: true diff --git a/apps/api/package.json b/apps/api/package.json index 45fe7dc..c31cb31 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -1,6 +1,6 @@ { "name": "pvdthings-api", - "version": "1.22.2", + "version": "1.23.0", "description": "", "main": "server.js", "scripts": { @@ -24,9 +24,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.21.0", - "helmet": "^8.0.0", - "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0" + "helmet": "^8.0.0" }, "devDependencies": { "jest": "^29.3.1" From fcb3f6d9ffa17abe99e7f5259524c432bbdfe084 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 21:16:47 -0500 Subject: [PATCH 10/35] remove /things route --- apps/api/server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/api/server.js b/apps/api/server.js index 7eabfee..f3bf13e 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -39,7 +39,6 @@ app.use(apiKeyMiddleware); app.use(bodyParser.json()); app.use('/web', things); -app.use('/things', things); app.use('/lending', lending); app.use((req, res, next) => { From bb0e9e4d89f54c58421fbe9f48d161b021328f12 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 16 Jan 2025 21:19:40 -0500 Subject: [PATCH 11/35] default to prod environment --- apps/api/utils/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/utils/environment.js b/apps/api/utils/environment.js index 241198f..2ecb62c 100644 --- a/apps/api/utils/environment.js +++ b/apps/api/utils/environment.js @@ -1,5 +1,5 @@ function isDevelopment() { - const environment = process.env.NODE_ENV || 'development'; + const environment = process.env.NODE_ENV || 'production'; return environment === 'development'; } From f174755005dd478dfea1b87a2f6e406a45f65680 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 22:18:28 -0500 Subject: [PATCH 12/35] api: update readme --- apps/api/README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/api/README.md b/apps/api/README.md index 84fd8cc..546460d 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -13,9 +13,6 @@ AIRTABLE_BASE_ID=[value] SUPABASE_URL=[value] SUPABASE_PUB_ANON_KEY=[value] -// Determines which Discord accounts are allowed to authenticate with the API -DISCORD_WHITELIST="alice@email.com bob@email.com" - // Determines which users can access admin features ADMIN_WHITELIST="alice@email.com" @@ -33,10 +30,4 @@ UPDATE_DUE_DATES_WEBHOOK_URL=[value] npm run install // on first run npm run start ``` -The server will start on port `8088`. - -When running locally, no authentication is needed for the `lending` API. In production environments, these endpoints require tokens provided by Supabase Authentication (via Discord). - -### Documentation - -**Swagger Docs** are hosted at [http://localhost:8088/docs](). \ No newline at end of file +The server will start on port `8088`. \ No newline at end of file From 331d2a8594558a4d3bfdce2f04a516d97e209e1d Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 22:18:40 -0500 Subject: [PATCH 13/35] remove docker composition --- apps/api/Dockerfile | 17 ----------------- apps/api/compose.yml | 13 ------------- 2 files changed, 30 deletions(-) delete mode 100644 apps/api/Dockerfile delete mode 100644 apps/api/compose.yml diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile deleted file mode 100644 index 26d178c..0000000 --- a/apps/api/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -ARG Port=8088 - -FROM node:20 as base - -ENV PORT $Port - -WORKDIR /api - -# Install Dependencies -COPY package.json package-lock.json ./ -RUN rm -rf node_modules && npm install - -# Copy Remaining Source -COPY . . - -EXPOSE $Port -CMD ["node", "./server.js"] \ No newline at end of file diff --git a/apps/api/compose.yml b/apps/api/compose.yml deleted file mode 100644 index a9d6d8a..0000000 --- a/apps/api/compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '4.28' -services: - api: - build: - context: . - dockerfile: ./Dockerfile - target: base - container_name: api - env_file: - - ./.env - image: api - ports: - - '${PORT}:${PORT}' \ No newline at end of file From 130d7091d4f8de6122a49967651f09dc9ef0696a Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 22:31:22 -0500 Subject: [PATCH 14/35] web: remove env script --- apps/web/src/lib/server/api.ts | 6 +++--- apps/web/src/lib/server/env.ts | 5 ----- .../web/src/routes/(app)/volunteer/+page.server.ts | 14 +++++++------- apps/web/src/routes/api/items/[id]/+server.ts | 6 +++--- apps/web/src/routes/api/things/[id]/+server.ts | 6 +++--- 5 files changed, 16 insertions(+), 21 deletions(-) delete mode 100644 apps/web/src/lib/server/env.ts diff --git a/apps/web/src/lib/server/api.ts b/apps/web/src/lib/server/api.ts index 136c2f0..280ef8b 100644 --- a/apps/web/src/lib/server/api.ts +++ b/apps/web/src/lib/server/api.ts @@ -1,10 +1,10 @@ +import { API_HOST, API_KEY } from "$env/static/private"; import type { AppData } from "$lib/models/AppData"; -import { HOST, KEY } from "./env"; export const fetchThings = async (fetch): Promise => { - const result = await fetch(`${HOST}/things`, { + const result = await fetch(`${API_HOST}/web/things`, { headers: { - 'x-api-key': KEY + 'x-api-key': API_KEY } }); diff --git a/apps/web/src/lib/server/env.ts b/apps/web/src/lib/server/env.ts deleted file mode 100644 index 40fe6fe..0000000 --- a/apps/web/src/lib/server/env.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { API_HOST, API_KEY } from "$env/static/private"; - -export const HOST = !!API_HOST ? API_HOST : 'http://localhost:8088'; - -export const KEY = API_KEY; \ No newline at end of file diff --git a/apps/web/src/routes/(app)/volunteer/+page.server.ts b/apps/web/src/routes/(app)/volunteer/+page.server.ts index 66efa5e..1570ec8 100644 --- a/apps/web/src/routes/(app)/volunteer/+page.server.ts +++ b/apps/web/src/routes/(app)/volunteer/+page.server.ts @@ -1,4 +1,4 @@ -import { HOST, KEY } from "$lib/server/env"; +import { API_HOST, API_KEY } from "$env/static/private"; import { fail } from "@sveltejs/kit"; export const load = async ({ cookies, fetch }): Promise => { @@ -6,9 +6,9 @@ export const load = async ({ cookies, fetch }): Promise => { const firstName = cookies.get('firstName'); const keyholder = cookies.get('keyholder'); - const response = await fetch(`${HOST}/web/volunteer/shifts`, { + const response = await fetch(`${API_HOST}/web/volunteer/shifts`, { headers: { - 'x-api-key': KEY, + 'x-api-key': API_KEY, 'x-email': email } }); @@ -30,11 +30,11 @@ export const actions = { return fail(400, { invalid: true }); } - const response = await fetch(`${HOST}/web/volunteer/auth`, { + const response = await fetch(`${API_HOST}/web/volunteer/auth`, { method: 'POST', headers: { 'content-type': 'application/json', - 'x-api-key': KEY + 'x-api-key': API_KEY }, body: JSON.stringify({ email }) }); @@ -63,11 +63,11 @@ export const actions = { const data = await request.formData(); const shifts = data.getAll('shifts').map((s) => JSON.parse(s.toString())); - const response = await fetch(`${HOST}/web/volunteer/shifts/enroll`, { + const response = await fetch(`${API_HOST}/web/volunteer/shifts/enroll`, { method: 'POST', headers: { 'content-type': 'application/json', - 'x-api-key': KEY, + 'x-api-key': API_KEY, 'x-email': email }, body: JSON.stringify({ shifts }) diff --git a/apps/web/src/routes/api/items/[id]/+server.ts b/apps/web/src/routes/api/items/[id]/+server.ts index c4de7da..700ed49 100644 --- a/apps/web/src/routes/api/items/[id]/+server.ts +++ b/apps/web/src/routes/api/items/[id]/+server.ts @@ -1,11 +1,11 @@ -import { HOST, KEY } from '$lib/server/env.js'; +import { API_HOST, API_KEY } from '$env/static/private'; export const GET = async ({ params }) => { const { id } = params; - return await fetch(`${HOST}/web/items/${id}`, { + return await fetch(`${API_HOST}/web/items/${id}`, { headers: { - 'x-api-key': KEY + 'x-api-key': API_KEY } }); }; \ No newline at end of file diff --git a/apps/web/src/routes/api/things/[id]/+server.ts b/apps/web/src/routes/api/things/[id]/+server.ts index 8fc9eea..d07c579 100644 --- a/apps/web/src/routes/api/things/[id]/+server.ts +++ b/apps/web/src/routes/api/things/[id]/+server.ts @@ -1,11 +1,11 @@ -import { HOST, KEY } from '$lib/server/env.js'; +import { API_HOST, API_KEY } from '$env/static/private'; export const GET = async ({ params }) => { const { id } = params; - return await fetch(`${HOST}/web/things/${id}`, { + return await fetch(`${API_HOST}/web/things/${id}`, { headers: { - 'x-api-key': KEY + 'x-api-key': API_KEY } }); }; \ No newline at end of file From 224375882fcbc7582560cb926c575f1d97875da8 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 22:33:57 -0500 Subject: [PATCH 15/35] web: move models into api folder --- apps/web/src/lib/{server => api}/api.ts | 2 +- apps/web/src/lib/{ => api}/models/AppData.ts | 0 apps/web/src/lib/{ => api}/models/ItemDetails.ts | 0 apps/web/src/lib/{ => api}/models/Thing.ts | 0 apps/web/src/lib/{ => api}/models/ThingDetails.ts | 0 apps/web/src/lib/stores/bookmarks.ts | 2 +- apps/web/src/lib/stores/catalog.ts | 2 +- apps/web/src/lib/stores/items.ts | 2 +- apps/web/src/lib/stores/things.ts | 2 +- apps/web/src/routes/(app)/+page.server.ts | 4 ++-- 10 files changed, 7 insertions(+), 7 deletions(-) rename apps/web/src/lib/{server => api}/api.ts (82%) rename apps/web/src/lib/{ => api}/models/AppData.ts (100%) rename apps/web/src/lib/{ => api}/models/ItemDetails.ts (100%) rename apps/web/src/lib/{ => api}/models/Thing.ts (100%) rename apps/web/src/lib/{ => api}/models/ThingDetails.ts (100%) diff --git a/apps/web/src/lib/server/api.ts b/apps/web/src/lib/api/api.ts similarity index 82% rename from apps/web/src/lib/server/api.ts rename to apps/web/src/lib/api/api.ts index 280ef8b..65eee02 100644 --- a/apps/web/src/lib/server/api.ts +++ b/apps/web/src/lib/api/api.ts @@ -1,5 +1,5 @@ import { API_HOST, API_KEY } from "$env/static/private"; -import type { AppData } from "$lib/models/AppData"; +import type { AppData } from "$lib/api/models/AppData"; export const fetchThings = async (fetch): Promise => { const result = await fetch(`${API_HOST}/web/things`, { diff --git a/apps/web/src/lib/models/AppData.ts b/apps/web/src/lib/api/models/AppData.ts similarity index 100% rename from apps/web/src/lib/models/AppData.ts rename to apps/web/src/lib/api/models/AppData.ts diff --git a/apps/web/src/lib/models/ItemDetails.ts b/apps/web/src/lib/api/models/ItemDetails.ts similarity index 100% rename from apps/web/src/lib/models/ItemDetails.ts rename to apps/web/src/lib/api/models/ItemDetails.ts diff --git a/apps/web/src/lib/models/Thing.ts b/apps/web/src/lib/api/models/Thing.ts similarity index 100% rename from apps/web/src/lib/models/Thing.ts rename to apps/web/src/lib/api/models/Thing.ts diff --git a/apps/web/src/lib/models/ThingDetails.ts b/apps/web/src/lib/api/models/ThingDetails.ts similarity index 100% rename from apps/web/src/lib/models/ThingDetails.ts rename to apps/web/src/lib/api/models/ThingDetails.ts diff --git a/apps/web/src/lib/stores/bookmarks.ts b/apps/web/src/lib/stores/bookmarks.ts index f83b6d5..cf78669 100644 --- a/apps/web/src/lib/stores/bookmarks.ts +++ b/apps/web/src/lib/stores/bookmarks.ts @@ -1,5 +1,5 @@ import { browser } from "$app/environment"; -import type { ThingID } from "$lib/models/Thing"; +import type { ThingID } from "$lib/api/models/Thing"; import { derived, writable } from "svelte/store"; const defaultValue = []; diff --git a/apps/web/src/lib/stores/catalog.ts b/apps/web/src/lib/stores/catalog.ts index 470f0c8..9b8ee99 100644 --- a/apps/web/src/lib/stores/catalog.ts +++ b/apps/web/src/lib/stores/catalog.ts @@ -1,4 +1,4 @@ -import type { Thing, ThingID } from "$lib/models/Thing"; +import type { Thing, ThingID } from "$lib/api/models/Thing"; import { defaultFilterCategory, filter } from "$lib/utils/filters"; import { derived, get, writable } from "svelte/store"; diff --git a/apps/web/src/lib/stores/items.ts b/apps/web/src/lib/stores/items.ts index 3efbb6b..66c9c9c 100644 --- a/apps/web/src/lib/stores/items.ts +++ b/apps/web/src/lib/stores/items.ts @@ -1,4 +1,4 @@ -import type { ItemDetailsModel } from "$lib/models/ItemDetails"; +import type { ItemDetailsModel } from "$lib/api/models/ItemDetails"; import { derived, get, readable, writable, type Readable } from "svelte/store"; import type { Async } from "./types"; diff --git a/apps/web/src/lib/stores/things.ts b/apps/web/src/lib/stores/things.ts index 6967f72..2635a78 100644 --- a/apps/web/src/lib/stores/things.ts +++ b/apps/web/src/lib/stores/things.ts @@ -1,4 +1,4 @@ -import type { ThingDetailsModel } from "$lib/models/ThingDetails"; +import type { ThingDetailsModel } from "$lib/api/models/ThingDetails"; import { derived, get, readable, writable, type Readable } from "svelte/store"; import type { Async } from "./types"; diff --git a/apps/web/src/routes/(app)/+page.server.ts b/apps/web/src/routes/(app)/+page.server.ts index 1be53a8..dad615d 100644 --- a/apps/web/src/routes/(app)/+page.server.ts +++ b/apps/web/src/routes/(app)/+page.server.ts @@ -1,5 +1,5 @@ -import type { AppData } from '$lib/models/AppData'; -import { fetchThings } from '$lib/server/api.js' +import type { AppData } from '$lib/api/models/AppData'; +import { fetchThings } from '$lib/api/api.js' export const load = async ({ fetch }): Promise => { return fetchThings(fetch); From 7cb10db4e6f1e87ba96cb0f8ebe083ab23ce693e Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 22:36:05 -0500 Subject: [PATCH 16/35] web: add readme for unused volunteer module --- apps/web/src/lib/volunteer/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/web/src/lib/volunteer/README.md diff --git a/apps/web/src/lib/volunteer/README.md b/apps/web/src/lib/volunteer/README.md new file mode 100644 index 0000000..98e2a62 --- /dev/null +++ b/apps/web/src/lib/volunteer/README.md @@ -0,0 +1 @@ +The `volunteer` module is currently inactive. \ No newline at end of file From ed6a76320369dd3092d55e98efbb460e103f2bbe Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:07:01 -0500 Subject: [PATCH 17/35] web: remove donations webhook script --- apps/web/src/lib/utils/donations.ts | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 apps/web/src/lib/utils/donations.ts diff --git a/apps/web/src/lib/utils/donations.ts b/apps/web/src/lib/utils/donations.ts deleted file mode 100644 index dfd2bc7..0000000 --- a/apps/web/src/lib/utils/donations.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const openDonationForm = (name: string) => { - const donateURL = `https://airtable.com/shrwMSrzvSLpQgQWC?prefill_Description=${encodeURIComponent(name)}`; - window.open(donateURL, '_blank').focus(); -}; \ No newline at end of file From 99d2eb234f063d1930c46336c062151fa17e35cb Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:07:24 -0500 Subject: [PATCH 18/35] web: move catalog load to page server --- apps/web/src/lib/api/api.ts | 12 ------------ apps/web/src/routes/(app)/+page.server.ts | 10 ++++++++-- 2 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 apps/web/src/lib/api/api.ts diff --git a/apps/web/src/lib/api/api.ts b/apps/web/src/lib/api/api.ts deleted file mode 100644 index 65eee02..0000000 --- a/apps/web/src/lib/api/api.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { API_HOST, API_KEY } from "$env/static/private"; -import type { AppData } from "$lib/api/models/AppData"; - -export const fetchThings = async (fetch): Promise => { - const result = await fetch(`${API_HOST}/web/things`, { - headers: { - 'x-api-key': API_KEY - } - }); - - return await result.json(); -}; \ No newline at end of file diff --git a/apps/web/src/routes/(app)/+page.server.ts b/apps/web/src/routes/(app)/+page.server.ts index dad615d..f04cc8e 100644 --- a/apps/web/src/routes/(app)/+page.server.ts +++ b/apps/web/src/routes/(app)/+page.server.ts @@ -1,6 +1,12 @@ import type { AppData } from '$lib/api/models/AppData'; -import { fetchThings } from '$lib/api/api.js' +import { API_HOST, API_KEY } from '$env/static/private'; export const load = async ({ fetch }): Promise => { - return fetchThings(fetch); + const result = await fetch(`${API_HOST}/web/catalog`, { + headers: { + 'x-api-key': API_KEY + } + }); + + return await result.json(); } \ No newline at end of file From 69bfd080c885e1c9e6aac858f9af3ed6c5647884 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:07:42 -0500 Subject: [PATCH 19/35] api: move catalog data to /web/catalog --- apps/api/apps/catalog/routes/things.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/apps/catalog/routes/things.js b/apps/api/apps/catalog/routes/things.js index 3bb7ee6..9596b94 100644 --- a/apps/api/apps/catalog/routes/things.js +++ b/apps/api/apps/catalog/routes/things.js @@ -6,7 +6,7 @@ const { getItemDetails } = require('../services/itemDetails'); // const { enroll, getShifts } = require('../services/shifts'); // const { findMember } = require('../../../services/borrowers'); -router.get('/', async (req, res) => { +router.get('/catalog', async (req, res) => { try { res.send(await getCatalogData()); } catch (error) { From 10cd55d268ada1933f904aa1ebbc46fb1fabff78 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:15:01 -0500 Subject: [PATCH 20/35] web: block search engine crawling --- apps/web/static/robots.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/web/static/robots.txt diff --git a/apps/web/static/robots.txt b/apps/web/static/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/apps/web/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file From 52d1bfb3ca7a85dd2963582cbaed4431b617adc2 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:15:17 -0500 Subject: [PATCH 21/35] web: version bump to 0.19.1 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index 5830d38..a53d81b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@library_os/web", - "version": "0.19.0", + "version": "0.19.1", "private": true, "scripts": { "dev": "vite dev", From 5f8a902ed5205a86edc7bbc6d8e1b2d5fd43e58f Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 18 Jan 2025 23:18:37 -0500 Subject: [PATCH 22/35] librarian: add robots.txt --- apps/librarian/web/robots.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/librarian/web/robots.txt diff --git a/apps/librarian/web/robots.txt b/apps/librarian/web/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/apps/librarian/web/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file From 144d8b58229b0fb74105adfc5d4f72931430db4a Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 21:19:33 -0500 Subject: [PATCH 23/35] api: remove deprecated code --- apps/api/apps/catalog/routes/things.js | 40 ---------------- apps/api/apps/catalog/services/shifts.js | 59 ----------------------- apps/api/services/auth.js | 6 --- apps/api/services/jobs/index.js | 3 -- apps/api/services/jobs/service.js | 60 ------------------------ 5 files changed, 168 deletions(-) delete mode 100644 apps/api/apps/catalog/services/shifts.js delete mode 100644 apps/api/services/jobs/index.js delete mode 100644 apps/api/services/jobs/service.js diff --git a/apps/api/apps/catalog/routes/things.js b/apps/api/apps/catalog/routes/things.js index 9596b94..af1a436 100644 --- a/apps/api/apps/catalog/routes/things.js +++ b/apps/api/apps/catalog/routes/things.js @@ -3,8 +3,6 @@ const router = express.Router(); const { getCatalogData } = require('../services/catalog'); const { getThingDetails } = require('../services/thingDetails'); const { getItemDetails } = require('../services/itemDetails'); -// const { enroll, getShifts } = require('../services/shifts'); -// const { findMember } = require('../../../services/borrowers'); router.get('/catalog', async (req, res) => { try { @@ -35,42 +33,4 @@ router.get('/items/:id', async (req, res) => { } }); -// router.get('/volunteer/shifts', async (req, res) => { -// const email = req.headers['x-email']; -// try { -// res.send(await getShifts({ email })); -// } catch (error) { -// console.error(error); -// res.status(error.status || 500).send({ errors: [error] }); -// } -// }); - -// router.post('/volunteer/auth', async (req, res) => { -// const { email } = req.body; -// try { -// const member = await findMember({ email }); - -// if (member) { -// res.send(member); -// } else { -// res.sendStatus(403); -// } -// } catch (error) { -// console.error(error); -// res.status(error.status || 500).send({ errors: [error] }); -// } -// }); - -// router.post('/volunteer/shifts/enroll', async (req, res) => { -// const email = req.headers['x-email']; -// const { shifts } = req.body; -// try { -// await enroll(email, shifts); -// res.sendStatus(204); -// } catch (error) { -// console.error(error); -// res.status(error.status || 500).send({ errors: [error] }); -// } -// }); - module.exports = router; \ No newline at end of file diff --git a/apps/api/apps/catalog/services/shifts.js b/apps/api/apps/catalog/services/shifts.js deleted file mode 100644 index af631e3..0000000 --- a/apps/api/apps/catalog/services/shifts.js +++ /dev/null @@ -1,59 +0,0 @@ -const { findMember } = require("../../../services/borrowers"); -const { fetchJobs, updateJobAssignments } = require("../../../services/jobs/service"); -const { sendJobsNotification } = require("../../../services/messages"); - -const dateFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' }; - -const formatTime = (date) => { - let hours = date.getHours(); - let minutes = date.getMinutes(); - let ampm = hours >= 12 ? 'pm' : 'am'; - - hours = hours % 12; hours = hours ? hours : 12; - minutes = minutes < 10 ? '0' + minutes : minutes; - return hours + ':' + minutes + ampm; -}; - -const getShifts = async ({ email }) => { - const member = await getMember(email); - const jobs = await fetchJobs(); - - return jobs.map((j) => { - const date = new Date(j.startTime); - let endDate = new Date(j.startTime); - endDate.setSeconds(date.getSeconds() + j.duration); - - return { - id: j.id, - title: j.title, - date: date.toLocaleString('en-US', dateFormatOptions), - timespan: `${formatTime(date)} - ${formatTime(endDate)}`, - description: j.description, - enrolled: j.members.some((m) => m.id === member?.id), - volunteers: j.members.filter((m) => m.id !== member?.id).map((m) => ({ - name: m.name, - firstName: m.name.split(' ')?.[0], - keyholder: m.keyholder - })) - }; - }); -}; - -const getMember = async (email) => { - return !!email ? await findMember({ email }) : undefined; -}; - -const enroll = async (email, shifts) => { - try { - updateJobAssignments(email, shifts).then(async () => { - const newShifts = shifts.filter((s) => !s.remove); - if (newShifts.length) { - await sendJobsNotification({ recipient: email, ids: newShifts.map((s) => s.id) }); - } - }); - } catch (error) { - throw error; - } -}; - -module.exports = { enroll, getShifts }; \ No newline at end of file diff --git a/apps/api/services/auth.js b/apps/api/services/auth.js index edd4f73..3645874 100644 --- a/apps/api/services/auth.js +++ b/apps/api/services/auth.js @@ -1,14 +1,8 @@ -const isWhitelisted = (email) => { - const whitelist = process.env.DISCORD_WHITELIST.split(' '); - return whitelist.includes(email); -}; - const isAdmin = (email) => { const whitelist = process.env.ADMIN_WHITELIST.split(' '); return whitelist.includes(email); }; module.exports = { - isWhitelisted, isAdmin }; \ No newline at end of file diff --git a/apps/api/services/jobs/index.js b/apps/api/services/jobs/index.js deleted file mode 100644 index 9d792ad..0000000 --- a/apps/api/services/jobs/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const { fetchJobs } = require('./service'); - -module.exports = { fetchJobs }; \ No newline at end of file diff --git a/apps/api/services/jobs/service.js b/apps/api/services/jobs/service.js deleted file mode 100644 index ed986a6..0000000 --- a/apps/api/services/jobs/service.js +++ /dev/null @@ -1,60 +0,0 @@ -const { base, Table } = require('../../db'); - -const jobs = base(Table.Jobs); -const members = base(Table.Borrowers); - -const fetchJobs = async () => { - const records = await jobs.select({ view: 'Future' }).all(); - - return await Promise.all(records.map(async (r) => { - const memberIds = r.get('Members') || []; - - return { - id: r.id, - title: r.get('Title'), - canceled: !!r.get('Canceled'), - description: r.get('Description'), - members: await Promise.all(memberIds.map(async (id) => { - const memberRecord = await members.find(id); - - return { - id: memberRecord.id, - name: memberRecord.get('Name'), - keyholder: !!memberRecord.get('Keyholder') - }; - })), - startTime: r.get('Start Time'), - duration: r.get('Duration') - }; - })); -}; - -const updateJobAssignments = async (email, jobs) => { - const matches = await members.select({ - filterByFormula: `{Email} = '${email}'` - }).all(); - - if (!matches.length) { - throw new Error('Email provided does not match any member.'); - } - - const memberRecord = matches[0]; - const existingJobs = memberRecord.get('Jobs') || []; - - const toAdd = jobs.filter((j) => !j.remove).map((j) => j.id); - const toRemove = jobs.filter((j) => !!j.remove).map((j) => j.id); - - const updatedJobs = [ - ...toAdd, - ...existingJobs.filter((id) => !toRemove.includes(id)) - ]; - - await memberRecord.updateFields({ - 'Jobs': updatedJobs - }); -}; - -module.exports = { - fetchJobs, - updateJobAssignments -}; \ No newline at end of file From 8454e99f68abbf94f40c7557e898c7fd8c781b49 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 21:19:48 -0500 Subject: [PATCH 24/35] api: update package.json info --- apps/api/package.json | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index c31cb31..e8a6299 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -3,20 +3,11 @@ "version": "1.23.0", "description": "", "main": "server.js", + "private": true, "scripts": { "test": "jest", "start": "node server.js" }, - "repository": { - "type": "git", - "url": "git+https://github.com/pvdthings/api.git" - }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/pvdthings/api/issues" - }, - "homepage": "https://github.com/pvdthings/api#readme", "dependencies": { "@supabase/supabase-js": "^2.45.4", "airtable": "^0.12.2", From 14c83d76ff47c36e684ad46ce52a67ba9b2c58a2 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 22:07:47 -0500 Subject: [PATCH 25/35] librarian: update deprecated meta tag --- apps/librarian/web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/librarian/web/index.html b/apps/librarian/web/index.html index c7bedc0..b6bb64a 100644 --- a/apps/librarian/web/index.html +++ b/apps/librarian/web/index.html @@ -21,7 +21,7 @@ - + From fb6dd18c4eb6240effcad77b82a1bacf43b11b46 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 22:34:56 -0500 Subject: [PATCH 26/35] api: rename public key var for supabase --- apps/api/middleware/supabaseAuthentication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/middleware/supabaseAuthentication.js b/apps/api/middleware/supabaseAuthentication.js index ca67bd3..8e3bbba 100644 --- a/apps/api/middleware/supabaseAuthentication.js +++ b/apps/api/middleware/supabaseAuthentication.js @@ -1,6 +1,6 @@ const { createClient } = require('@supabase/supabase-js'); -const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUB_ANON_KEY); +const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_PUBLIC_KEY); const authenticateToken = async (req, res, next) => { const accessToken = req.headers['x-access-token']; From db55beb43cd9b1aec4f0f542c504b6f626b95caf Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 22:42:21 -0500 Subject: [PATCH 27/35] api: update readme with new env var name --- apps/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/README.md b/apps/api/README.md index 546460d..e6a02ae 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -11,7 +11,7 @@ AIRTABLE_KEY=[value] AIRTABLE_BASE_ID=[value] SUPABASE_URL=[value] -SUPABASE_PUB_ANON_KEY=[value] +SUPABASE_PUBLIC_KEY=[value] // Determines which users can access admin features ADMIN_WHITELIST="alice@email.com" From 23e667257111445f15c71dd566da7b7a8fa54c4c Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Tue, 21 Jan 2025 22:48:49 -0500 Subject: [PATCH 28/35] web: remove remaining volunteer code --- .../src/lib/views/BottomNavigationView.svelte | 7 -- apps/web/src/lib/volunteer/README.md | 1 - apps/web/src/lib/volunteer/ShiftCard.svelte | 88 -------------- apps/web/src/lib/volunteer/ShiftsView.svelte | 114 ------------------ .../routes/(app)/volunteer/+page.server.ts | 78 ------------ .../src/routes/(app)/volunteer/+page.svelte | 12 -- 6 files changed, 300 deletions(-) delete mode 100644 apps/web/src/lib/volunteer/README.md delete mode 100644 apps/web/src/lib/volunteer/ShiftCard.svelte delete mode 100644 apps/web/src/lib/volunteer/ShiftsView.svelte delete mode 100644 apps/web/src/routes/(app)/volunteer/+page.server.ts delete mode 100644 apps/web/src/routes/(app)/volunteer/+page.svelte diff --git a/apps/web/src/lib/views/BottomNavigationView.svelte b/apps/web/src/lib/views/BottomNavigationView.svelte index 929bf10..a626e91 100644 --- a/apps/web/src/lib/views/BottomNavigationView.svelte +++ b/apps/web/src/lib/views/BottomNavigationView.svelte @@ -15,7 +15,6 @@ $: catalogText = $t('Catalog'); $: bookmarksText = $t('Bookmarks'); $: learnText = $t('Learn'); - // $: volunteerText = $t('Volunteer'); @@ -38,10 +37,4 @@ label={learnText} on:click={() => goto('/info')} /> - diff --git a/apps/web/src/lib/volunteer/README.md b/apps/web/src/lib/volunteer/README.md deleted file mode 100644 index 98e2a62..0000000 --- a/apps/web/src/lib/volunteer/README.md +++ /dev/null @@ -1 +0,0 @@ -The `volunteer` module is currently inactive. \ No newline at end of file diff --git a/apps/web/src/lib/volunteer/ShiftCard.svelte b/apps/web/src/lib/volunteer/ShiftCard.svelte deleted file mode 100644 index ffd045d..0000000 --- a/apps/web/src/lib/volunteer/ShiftCard.svelte +++ /dev/null @@ -1,88 +0,0 @@ - - -
-
-
-
{date}
-
{time}
-
{title}
- {#if description?.length} -
{description}
- {/if} -
-
-
- {#if (selected || enrolled) && !removed} - - {:else} - - {/if} -
- - {#if unsavedChanges} -
*not saved
- {/if} -
-
- -
-
Volunteers
-
- {#if !volunteers.some((v) => v.keyholder) && !enrolled} -
- - No Keyholder -
- {/if} - - {#if enrolled} -
- {#if getContext('user')?.keyholder} - - {/if} - Me -
- {/if} - - {#each volunteers as volunteer} -
- {#if volunteer.keyholder} - - {/if} - {volunteer.firstName} -
- {/each} -
-
-
diff --git a/apps/web/src/lib/volunteer/ShiftsView.svelte b/apps/web/src/lib/volunteer/ShiftsView.svelte deleted file mode 100644 index 9da2356..0000000 --- a/apps/web/src/lib/volunteer/ShiftsView.svelte +++ /dev/null @@ -1,114 +0,0 @@ - - -
-
- {#if !loggedIn} -
- - -
- {:else} -
- {#if firstName} -
- Hi, {firstName}. -
- {/if} -
- {pluralize(totalAssigned(), 'shift')} - -
-
-
- {#each modifiedShifts as shift} - - {/each} - - -
- {/if} -
- - {#if unauthorized} -
- - {email} could not be matched to any existing member. - Please show up for the shift you wanted to join and we'll get you set up. - -
- {/if} - - {#each shifts as shift} - s.id === shift.id)} - volunteers={shift.volunteers} - onAdd={loggedIn ? (id) => modify(id) : undefined} - onRemove={loggedIn ? (id) => modify(id, true) : undefined} - /> - {/each} -
- -{#if loggedIn} -
- -
-{/if} \ No newline at end of file diff --git a/apps/web/src/routes/(app)/volunteer/+page.server.ts b/apps/web/src/routes/(app)/volunteer/+page.server.ts deleted file mode 100644 index 1570ec8..0000000 --- a/apps/web/src/routes/(app)/volunteer/+page.server.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { API_HOST, API_KEY } from "$env/static/private"; -import { fail } from "@sveltejs/kit"; - -export const load = async ({ cookies, fetch }): Promise => { - const email = cookies.get('email'); - const firstName = cookies.get('firstName'); - const keyholder = cookies.get('keyholder'); - - const response = await fetch(`${API_HOST}/web/volunteer/shifts`, { - headers: { - 'x-api-key': API_KEY, - 'x-email': email - } - }); - - return { - shifts: await response.json(), - authenticated: !!email, - firstName, - keyholder: !!email && keyholder - }; -}; - -export const actions = { - authenticate: async ({ cookies, fetch, request }) => { - const data = await request.formData(); - const email = data.get('email').toString().toLowerCase(); - - if (!email) { - return fail(400, { invalid: true }); - } - - const response = await fetch(`${API_HOST}/web/volunteer/auth`, { - method: 'POST', - headers: { - 'content-type': 'application/json', - 'x-api-key': API_KEY - }, - body: JSON.stringify({ email }) - }); - - if (response.ok) { - const member = await response.json(); - - cookies.set('firstName', member.name.split(' ')?.[0], { path: '/' }); - cookies.set('email', email, { path: '/' }); - cookies.set('keyholder', member.keyholder, { path: '/' }); - - return { success: true }; - } - - return fail(403, { email, unauthorized: response.status === 403 }); - }, - unauthenticate: async ({ cookies }) => { - cookies.delete('firstName', { path: '/' }); - cookies.delete('email', { path: '/' }); - cookies.delete('keyholder', { path: '/' }); - return { success: true }; - }, - confirm: async ({ cookies, fetch, request }) => { - const email = cookies.get('email'); - - const data = await request.formData(); - const shifts = data.getAll('shifts').map((s) => JSON.parse(s.toString())); - - const response = await fetch(`${API_HOST}/web/volunteer/shifts/enroll`, { - method: 'POST', - headers: { - 'content-type': 'application/json', - 'x-api-key': API_KEY, - 'x-email': email - }, - body: JSON.stringify({ shifts }) - }); - - return { success: response.ok }; - } -}; \ No newline at end of file diff --git a/apps/web/src/routes/(app)/volunteer/+page.svelte b/apps/web/src/routes/(app)/volunteer/+page.svelte deleted file mode 100644 index aa10e2f..0000000 --- a/apps/web/src/routes/(app)/volunteer/+page.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - -
- -
From 8ec6557493b11ae38ebc608eda7264c7360b29fc Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 23 Jan 2025 08:50:08 -0500 Subject: [PATCH 29/35] librarian: remove dotenv package --- .gitignore | 3 +++ apps/librarian/lib/constants.dart | 22 ++++------------------ apps/librarian/lib/main.dart | 2 -- apps/librarian/pubspec.lock | 20 ++++++-------------- apps/librarian/pubspec.yaml | 3 --- 5 files changed, 13 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 8a0b44a..eb13fec 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# Launch +.vscode \ No newline at end of file diff --git a/apps/librarian/lib/constants.dart b/apps/librarian/lib/constants.dart index a6f9792..0fee0c6 100644 --- a/apps/librarian/lib/constants.dart +++ b/apps/librarian/lib/constants.dart @@ -1,24 +1,10 @@ -import 'package:flutter_dotenv/flutter_dotenv.dart'; - -Future loadEnvironmentVariables() async { - await dotenv.load(isOptional: true); -} - const supabaseUrlKey = 'SUPABASE_URL'; const supabasePublicKeyKey = 'SUPABASE_PUBLIC_KEY'; const apiHostKey = 'API_HOST'; const apiKeyKey = 'API_KEY'; const appUrlKey = 'APP_URL'; -const String _supabaseUrl = String.fromEnvironment(supabaseUrlKey); -const String _supabasePublicKey = String.fromEnvironment(supabasePublicKeyKey); -const String _apiHost = String.fromEnvironment(apiHostKey); -const String _apiKey = String.fromEnvironment(apiKeyKey); -const String _appUrl = String.fromEnvironment(appUrlKey); - -String get supabaseUrl => dotenv.get(supabaseUrlKey, fallback: _supabaseUrl); -String get supabasePublicKey => - dotenv.get(supabasePublicKeyKey, fallback: _supabasePublicKey); -String get apiHost => dotenv.get(apiHostKey, fallback: _apiHost); -String get apiKey => dotenv.get(apiKeyKey, fallback: _apiKey); -String get appUrl => dotenv.get(appUrlKey, fallback: _appUrl); +const apiHost = String.fromEnvironment(apiHostKey); +const apiKey = String.fromEnvironment(apiKeyKey); +const supabaseUrl = String.fromEnvironment(supabaseUrlKey); +const supabasePublicKey = String.fromEnvironment(supabasePublicKeyKey); diff --git a/apps/librarian/lib/main.dart b/apps/librarian/lib/main.dart index c949d04..9de9123 100644 --- a/apps/librarian/lib/main.dart +++ b/apps/librarian/lib/main.dart @@ -1,13 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart' as riverpod; -import 'package:librarian_app/constants.dart'; import 'package:librarian_app/core/supabase.dart'; import 'package:librarian_app/modules/splash/pages/splash_page.dart'; import 'package:librarian_app/theme/indigo_theme.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - await loadEnvironmentVariables(); initializeSupabase(); runApp(const riverpod.ProviderScope( diff --git a/apps/librarian/pubspec.lock b/apps/librarian/pubspec.lock index 2d94105..0ff5557 100644 --- a/apps/librarian/pubspec.lock +++ b/apps/librarian/pubspec.lock @@ -331,14 +331,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_dotenv: - dependency: "direct main" - description: - name: flutter_dotenv - sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b - url: "https://pub.dev" - source: hosted - version: "5.2.1" flutter_lints: dependency: "direct dev" description: @@ -433,10 +425,10 @@ packages: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.3.0" http_multi_server: dependency: transitive description: @@ -761,10 +753,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: bf808be89fe9dc467475e982c1db6c2faf3d2acf54d526cd5ec37d86c99dbd84 + sha256: "138b7bbbc7f59c56236e426c37afb8f78cbc57b094ac64c440e0bb90e380a4f5" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_foundation: dependency: transitive description: @@ -1070,10 +1062,10 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" win32: dependency: transitive description: diff --git a/apps/librarian/pubspec.yaml b/apps/librarian/pubspec.yaml index 4daf301..be3a25e 100644 --- a/apps/librarian/pubspec.yaml +++ b/apps/librarian/pubspec.yaml @@ -40,7 +40,6 @@ dependencies: url_launcher: ^6.2.5 skeletonizer: ^1.4.2 phone_numbers_parser: ^9.0.2 - flutter_dotenv: ^5.2.1 dev_dependencies: flutter_test: @@ -70,8 +69,6 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - web/assets/ - - .env - # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware From 136c32347676c3a874f51e038b0e17f8096bc546 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 23 Jan 2025 08:50:25 -0500 Subject: [PATCH 30/35] librarian: update readme for launch file --- apps/librarian/README.md | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/librarian/README.md b/apps/librarian/README.md index 1331edc..39c8ccc 100644 --- a/apps/librarian/README.md +++ b/apps/librarian/README.md @@ -6,29 +6,48 @@ Librarian is the first app in **Library OS**. It is intended to be used by volun ## Running the app -### Set environment variables +### Environment variables ``` API_HOST (http://localhost:8088/lending) API_KEY -APP_URL + SUPABASE_URL SUPABASE_PUBLIC_KEY ``` -Supabase variables are required for production environments, but not for local development. - -### Launch in Chrome +Environment variables are passed in when running the app. ``` -flutter run -d chrome +flutter run -d chrome --dart-define VAR=value ``` -For a better debugging experience, use the Flutter dev tools in Visual Studio Code. +To simplify configuration during development, it's recommeneded to use Visual Studio Code and create a `launch.json` file at the root of the `library_os` folder. + +Your configuration will look something like this: + +```json +{ + "name": "librarian", + "cwd": "apps/librarian", + "request": "launch", + "type": "dart", + "args": [ + "--dart-define", "API_KEY=value", + "--dart-define", "API_HOST=http://localhost:8088/lending", + "--dart-define", "SUPABASE_URL=value", + "--dart-define", "SUPABASE_PUBLIC_KEY=value" + ] +} +``` + +### Launch in Chrome + +Use Visual Studio's `Run and Debug` feature to launch the app in Chrome. ## Project Structure -The repository is organized "feature-first," so things become more specific as you go down the folder hierarchy. +The repository is (mostly) organized "feature-first," so things become more specific as you go down the folder hierarchy. - `core` folders contain **Business Logic**. - `data` folders contain **Repostories**. From f55904cf1f2e2e3aa49dcd9909e36d904b1b2f79 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 23 Jan 2025 09:00:33 -0500 Subject: [PATCH 31/35] librarian: fix previous loan dialog --- .../loans/details/loan_details_controller.dart | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/librarian/lib/modules/loans/details/loan_details_controller.dart b/apps/librarian/lib/modules/loans/details/loan_details_controller.dart index be745d1..a18b282 100644 --- a/apps/librarian/lib/modules/loans/details/loan_details_controller.dart +++ b/apps/librarian/lib/modules/loans/details/loan_details_controller.dart @@ -27,15 +27,9 @@ class LoanDetailsController { return GeneralDialog( titlePrefix: ThingNumber(number: itemNumber), title: 'Previous Loan', - content: SingleChildScrollView( - controller: ScrollController(), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: PreviousLoanDetails( - loanId: id, - itemId: itemId, - ), - ), + content: PreviousLoanDetails( + loanId: id, + itemId: itemId, ), ); }, From f1671079f4929f2207511e4450debc6543f9265c Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 23 Jan 2025 18:37:40 -0500 Subject: [PATCH 32/35] librarian: update structure section --- apps/librarian/README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/librarian/README.md b/apps/librarian/README.md index 39c8ccc..66e9449 100644 --- a/apps/librarian/README.md +++ b/apps/librarian/README.md @@ -45,13 +45,6 @@ Your configuration will look something like this: Use Visual Studio's `Run and Debug` feature to launch the app in Chrome. -## Project Structure +## Project structure The repository is (mostly) organized "feature-first," so things become more specific as you go down the folder hierarchy. - -- `core` folders contain **Business Logic**. -- `data` folders contain **Repostories**. -- `models` contains **Models** or **ViewModels**. -- `providers` folders contain **Providers**, which maintain shared app state and notify widgets of changes. -- `widgets` folders contain **UI Widgets** (and controllers) that compose larger widgets or pages. -- `pages` folders contain UI widgets that represent pages. These are generally wrapped in a `Scaffold` widget. \ No newline at end of file From a324ab8ef81b4284056c1b1dc4fd3f4c1a91dce1 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Thu, 23 Jan 2025 19:15:50 -0500 Subject: [PATCH 33/35] librarian: remove refresh token from api requests --- apps/librarian/lib/core/api/dio_client.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/librarian/lib/core/api/dio_client.dart b/apps/librarian/lib/core/api/dio_client.dart index 0d301b6..d555af8 100644 --- a/apps/librarian/lib/core/api/dio_client.dart +++ b/apps/librarian/lib/core/api/dio_client.dart @@ -4,9 +4,6 @@ class DioClient { static String get _accessToken => supabase.auth.currentSession?.accessToken ?? ''; - static String get _refreshToken => - supabase.auth.currentSession?.refreshToken ?? ''; - static BaseOptions get _options { return BaseOptions( baseUrl: apiHost, @@ -14,7 +11,6 @@ class DioClient { headers: { 'x-api-key': apiKey, 'x-access-token': _accessToken, - 'x-refresh-token': _refreshToken, }, ); } From 31f805fd95eac6709fa1d16a58f5211d1b4419e3 Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 25 Jan 2025 12:29:13 -0500 Subject: [PATCH 34/35] web: update package-lock --- apps/web/package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index fc22b0a..7598d84 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "@library_os/web", - "version": "0.19.0", + "version": "0.19.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@library_os/web", - "version": "0.19.0", + "version": "0.19.1", "dependencies": { "@phosphor-icons/web": "^2.1.1" }, From 2ffb89fe6fb775e86c4f987a2fa8a8d4b01afb9c Mon Sep 17 00:00:00 2001 From: Dillon Fagan Date: Sat, 25 Jan 2025 13:00:07 -0500 Subject: [PATCH 35/35] api: add env var to disable lending module --- apps/api/server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/api/server.js b/apps/api/server.js index f3bf13e..904e961 100644 --- a/apps/api/server.js +++ b/apps/api/server.js @@ -39,7 +39,10 @@ app.use(apiKeyMiddleware); app.use(bodyParser.json()); app.use('/web', things); -app.use('/lending', lending); + +if (!process.env.DISABLE_LENDING) { + app.use('/lending', lending); +} app.use((req, res, next) => { res.status(404).send();