From 11c19505c8cde7ec0aecf28dec5c8a2c5b3b9c01 Mon Sep 17 00:00:00 2001 From: kike454 Date: Sun, 18 May 2025 18:06:58 +0200 Subject: [PATCH 1/9] feat: add providers --- src/controllers/provider.ts | 132 ++++++++++++++++++++++++++++++++++++ src/router/index.ts | 2 + src/router/provider.ts | 25 +++++++ src/schemas/provider.ts | 8 +++ 4 files changed, 167 insertions(+) create mode 100644 src/controllers/provider.ts create mode 100644 src/router/provider.ts create mode 100644 src/schemas/provider.ts diff --git a/src/controllers/provider.ts b/src/controllers/provider.ts new file mode 100644 index 0000000..c544428 --- /dev/null +++ b/src/controllers/provider.ts @@ -0,0 +1,132 @@ +import { Provider } from "../schemas/provider"; + +export const getProviders = async (req, res) => { + try { + const providers = await Provider.find(); + + if (!providers || providers.length === 0) { + return res.status(404).json({ + message: 'No providers found', + status: 'failure' + }); + } + + return res.status(200).json({ + items: providers, + count: providers.length, + message: 'Providers data fetched successfully', + status: 'success' + }); + + } catch (error) { + return res.status(500).json({ + message: 'Error fetching providers', + status: 'failure' + }); + } +}; + +export const getProviderById = async (req, res) => { + const { id } = req.params; + + try { + const provider = await Provider.findById(id); + + if (!provider) { + return res.status(404).json({ + message: 'Provider not found', + status: 'failure' + }); + } + + return res.status(200).json({ + items: provider, + message: 'Provider data fetched successfully', + status: 'success' + }); + + } catch (error) { + return res.status(500).json({ + message: 'Error fetching provider', + status: 'failure' + }); + } +}; + +export const createProvider = async (req, res) => { + try { + const providerData = req.body; + + if (!providerData.name || !providerData.contact_email) { + return res.status(400).json({ + message: 'Invalid input data', + status: 'failure' + }); + } + + const provider = await Provider.insertOne(providerData); + + return res.status(201).json({ + items: provider, + message: 'Provider created successfully', + status: 'success' + }); + + } catch (error) { + return res.status(500).json({ + message: 'Error creating provider', + status: 'failure' + }); + } +}; + +export const updateProviderById = async (req, res) => { + const { id } = req.params; + const updateData = req.body; + + try { + const provider = await Provider.findByIdAndUpdate(id, updateData, { new: true }); + + if (!provider) { + return res.status(404).json({ + message: 'Provider not found', + status: 'failure' + }); + } + + return res.status(200).json({ + items: provider, + message: 'Provider updated successfully', + status: 'success' + }); + + } catch (error) { + return res.status(500).json({ + message: 'Error updating provider', + status: 'failure' + }); + } +}; + +export const deleteProviderById = async (req, res) => { + const { id } = req.params; + + try { + const provider = await Provider.findByIdAndDelete(id); + + if (!provider) { + return res.status(404).json({ + message: 'Provider not found', + status: 'failure' + }); + } + + return res.status(204).send(); + + } catch (error) { + return res.status(500).json({ + message: 'Error deleting provider', + status: 'failure' + }); + } +}; diff --git a/src/router/index.ts b/src/router/index.ts index cb013e4..a14eccd 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,11 +1,13 @@ import express from 'express'; import sneakersRouter from './sneakers'; import storesRouter from './stores'; +import providersRouter from './provider'; const router = express.Router() router.use('/sneakers', sneakersRouter); router.use('/stores', storesRouter); +router.use('/providers', providersRouter); export default router; \ No newline at end of file diff --git a/src/router/provider.ts b/src/router/provider.ts new file mode 100644 index 0000000..4fd1f75 --- /dev/null +++ b/src/router/provider.ts @@ -0,0 +1,25 @@ +import express from 'express'; +import { + getProviders, + getProviderById, + createProvider, + updateProviderById, + deleteProviderById +} from '../controllers/provider'; + +const providersRouter = express.Router(); + +// GET +providersRouter.get('/', getProviders); +providersRouter.get('/:id', getProviderById); + +// POST +providersRouter.post('/', createProvider); + +// PUT +providersRouter.put('/:id', updateProviderById); + +// DELETE +providersRouter.delete('/:id', deleteProviderById); + +export default providersRouter; diff --git a/src/schemas/provider.ts b/src/schemas/provider.ts new file mode 100644 index 0000000..562c558 --- /dev/null +++ b/src/schemas/provider.ts @@ -0,0 +1,8 @@ +import mongoose from "mongoose"; + +const providerSchema = new mongoose.Schema({ + name: { type: String, required: true }, + contact_email: { type: String, required: true } +}); + +export const Provider = mongoose.model('Provider', providerSchema); From 9cbcdf7baaf29d26440c8e2526aab326a8b2a591 Mon Sep 17 00:00:00 2001 From: pablogaraay Date: Mon, 19 May 2025 13:24:28 +0200 Subject: [PATCH 2/9] Added Providers JSON --- seeds/providers/providers.json | 402 +++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 seeds/providers/providers.json diff --git a/seeds/providers/providers.json b/seeds/providers/providers.json new file mode 100644 index 0000000..835ed7e --- /dev/null +++ b/seeds/providers/providers.json @@ -0,0 +1,402 @@ +[ + { + "name": "Nike", + "contact_email": "support@nike.com" + }, + { + "name": "Adidas", + "contact_email": "support@adidas.com" + }, + { + "name": "Puma", + "contact_email": "support@puma.com" + }, + { + "name": "Reebok", + "contact_email": "support@reebok.com" + }, + { + "name": "New Balance", + "contact_email": "support@newbalance.com" + }, + { + "name": "Under Armour", + "contact_email": "support@underarmour.com" + }, + { + "name": "Asics", + "contact_email": "support@asics.com" + }, + { + "name": "Converse", + "contact_email": "support@converse.com" + }, + { + "name": "Vans", + "contact_email": "support@vans.com" + }, + { + "name": "Fila", + "contact_email": "support@fila.com" + }, + { + "name": "Brooks", + "contact_email": "support@brooks.com" + }, + { + "name": "Saucony", + "contact_email": "support@saucony.com" + }, + { + "name": "Skechers", + "contact_email": "support@skechers.com" + }, + { + "name": "Mizuno", + "contact_email": "support@mizuno.com" + }, + { + "name": "Jordan", + "contact_email": "support@jordan.com" + }, + { + "name": "New Era", + "contact_email": "support@newera.com" + }, + { + "name": "DC Shoes", + "contact_email": "support@dcshoes.com" + }, + { + "name": "Burton", + "contact_email": "support@burton.com" + }, + { + "name": "The North Face", + "contact_email": "support@thenorthface.com" + }, + { + "name": "Columbia", + "contact_email": "support@columbia.com" + }, + { + "name": "Salomon", + "contact_email": "support@salomon.com" + }, + { + "name": "Merrell", + "contact_email": "support@merrell.com" + }, + { + "name": "Patagonia", + "contact_email": "support@patagonia.com" + }, + { + "name": "Arc'teryx", + "contact_email": "support@arcteryx.com" + }, + { + "name": "Hoka One One", + "contact_email": "support@hokaoneone.com" + }, + { + "name": "Altra", + "contact_email": "support@altra.com" + }, + { + "name": "On Running", + "contact_email": "support@onrunning.com" + }, + { + "name": "Vibram", + "contact_email": "support@vibram.com" + }, + { + "name": "K-Swiss", + "contact_email": "support@k-swiss.com" + }, + { + "name": "Lululemon", + "contact_email": "support@lululemon.com" + }, + { + "name": "Karhu", + "contact_email": "support@karhu.com" + }, + { + "name": "Diadora", + "contact_email": "support@diadora.com" + }, + { + "name": "Ecco", + "contact_email": "support@ecco.com" + }, + { + "name": "Gola", + "contact_email": "support@gola.com" + }, + { + "name": "KangaROOS", + "contact_email": "support@kangaroos.com" + }, + { + "name": "Le Coq Sportif", + "contact_email": "support@lecoqsportif.com" + }, + { + "name": "Veja", + "contact_email": "support@veja.com" + }, + { + "name": "Allbirds", + "contact_email": "support@allbirds.com" + }, + { + "name": "Koio", + "contact_email": "support@koio.com" + }, + { + "name": "Cariuma", + "contact_email": "support@cariuma.com" + }, + { + "name": "Novesta", + "contact_email": "support@novesta.com" + }, + { + "name": "Danner", + "contact_email": "support@danner.com" + }, + { + "name": "Clarks", + "contact_email": "support@clarks.com" + }, + { + "name": "TOMS", + "contact_email": "support@toms.com" + }, + { + "name": "Supra", + "contact_email": "support@supra.com" + }, + { + "name": "Golden Goose", + "contact_email": "support@goldengoose.com" + }, + { + "name": "Common Projects", + "contact_email": "support@commonprojects.com" + }, + { + "name": "BAPE", + "contact_email": "support@bape.com" + }, + { + "name": "Yeezy", + "contact_email": "support@yeezy.com" + }, + { + "name": "Li-Ning", + "contact_email": "support@li-ning.com" + }, + { + "name": "Peak", + "contact_email": "support@peak.com" + }, + { + "name": "Anta", + "contact_email": "support@anta.com" + }, + { + "name": "361 Degrees", + "contact_email": "support@361degrees.com" + }, + { + "name": "Air Jordan", + "contact_email": "support@airjordan.com" + }, + { + "name": "Y-3", + "contact_email": "support@y-3.com" + }, + { + "name": "Off-White", + "contact_email": "support@off-white.com" + }, + { + "name": "Balenciaga", + "contact_email": "support@balenciaga.com" + }, + { + "name": "Gucci", + "contact_email": "support@gucci.com" + }, + { + "name": "Dior", + "contact_email": "support@dior.com" + }, + { + "name": "Dolce & Gabbana", + "contact_email": "support@dolcegabbana.com" + }, + { + "name": "Moschino", + "contact_email": "support@moschino.com" + }, + { + "name": "Alexander McQueen", + "contact_email": "support@alexandermcqueen.com" + }, + { + "name": "Prada", + "contact_email": "support@prada.com" + }, + { + "name": "Versace", + "contact_email": "support@versace.com" + }, + { + "name": "Saint Laurent", + "contact_email": "support@saintlaurent.com" + }, + { + "name": "Givenchy", + "contact_email": "support@givenchy.com" + }, + { + "name": "Fendi", + "contact_email": "support@fendi.com" + }, + { + "name": "Valentino", + "contact_email": "support@valentino.com" + }, + { + "name": "Chanel", + "contact_email": "support@chanel.com" + }, + { + "name": "Balmain", + "contact_email": "support@balmain.com" + }, + { + "name": "Undercover", + "contact_email": "support@undercover.com" + }, + { + "name": "Maison Margiela", + "contact_email": "support@maisonmargiela.com" + }, + { + "name": "Rick Owens", + "contact_email": "support@rickowens.com" + }, + { + "name": "Veja x Rick Owens", + "contact_email": "support@vejaxrickowens.com" + }, + { + "name": "Nike SB", + "contact_email": "support@nikesb.com" + }, + { + "name": "Adidas Originals", + "contact_email": "support@adidasoriginals.com" + }, + { + "name": "Puma Select", + "contact_email": "support@pumaselect.com" + }, + { + "name": "New Balance Numeric", + "contact_email": "support@newbalancenumeric.com" + }, + { + "name": "Saucony Originals", + "contact_email": "support@sauconyoriginals.com" + }, + { + "name": "Converse Chuck", + "contact_email": "support@conversechuck.com" + }, + { + "name": "Vans Vault", + "contact_email": "support@vansvault.com" + }, + { + "name": "Reebok Classics", + "contact_email": "support@reebokclassics.com" + }, + { + "name": "Asics Tiger", + "contact_email": "support@asicstiger.com" + }, + { + "name": "Onitsuka Tiger", + "contact_email": "support@onitsukatiger.com" + }, + { + "name": "Under Armour HOVR", + "contact_email": "support@underarmourhovr.com" + }, + { + "name": "Skechers Sport", + "contact_email": "support@skecherssport.com" + }, + { + "name": "Merrell Moab", + "contact_email": "support@merrellmoab.com" + }, + { + "name": "Salomon Speedcross", + "contact_email": "support@salomonspeedcross.com" + }, + { + "name": "Patagonia Footwear", + "contact_email": "support@patagoniafootwear.com" + }, + { + "name": "Arc'teryx Veilance", + "contact_email": "support@arcteryxveilance.com" + }, + { + "name": "Hoka EVO", + "contact_email": "support@hokaevo.com" + }, + { + "name": "Altra Escalante", + "contact_email": "support@altraescalante.com" + }, + { + "name": "On Cloud", + "contact_email": "support@oncloud.com" + }, + { + "name": "Vibram FiveFingers", + "contact_email": "support@vibramfivefingers.com" + }, + { + "name": "K-Swiss Classic", + "contact_email": "support@k-swissclassic.com" + }, + { + "name": "Lululemon Surge", + "contact_email": "support@lululemonsurge.com" + }, + { + "name": "Karhu Fusion", + "contact_email": "support@karhufusion.com" + }, + { + "name": "Diadora Heritage", + "contact_email": "support@diadoraheritage.com" + }, + { + "name": "Ecco Biom", + "contact_email": "support@eccobiom.com" + }, + { + "name": "Gola Classics", + "contact_email": "support@golaclassics.com" + } + ] \ No newline at end of file From 2ee7adc5360c16c5216abc95300465fc9858b721 Mon Sep 17 00:00:00 2001 From: pablogaraay Date: Mon, 19 May 2025 13:31:37 +0200 Subject: [PATCH 3/9] provider schema fixed --- src/schemas/provider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/schemas/provider.ts b/src/schemas/provider.ts index 562c558..f8664e3 100644 --- a/src/schemas/provider.ts +++ b/src/schemas/provider.ts @@ -1,6 +1,7 @@ import mongoose from "mongoose"; const providerSchema = new mongoose.Schema({ + _id: { type: String }, name: { type: String, required: true }, contact_email: { type: String, required: true } }); From 478ff04e6be653fb3ffa8450e528e6d522a23ab0 Mon Sep 17 00:00:00 2001 From: pablogaraay Date: Mon, 19 May 2025 13:40:12 +0200 Subject: [PATCH 4/9] provider schema email validation fixed --- package.json | 3 ++- src/schemas/provider.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2d120c6..f1ada60 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dotenv": "^16.5.0", "express": "^4.21.2", "mongoose": "^8.15.0", - "ts-node": "^10.9.2" + "ts-node": "^10.9.2", + "validator": "^13.15.0" } } diff --git a/src/schemas/provider.ts b/src/schemas/provider.ts index f8664e3..4b3cf17 100644 --- a/src/schemas/provider.ts +++ b/src/schemas/provider.ts @@ -1,9 +1,10 @@ import mongoose from "mongoose"; +import isEmail from 'validator/lib/isEmail'; const providerSchema = new mongoose.Schema({ _id: { type: String }, name: { type: String, required: true }, - contact_email: { type: String, required: true } + contact_email: { type: String, required: true, validate: {validator: (v: string) => isEmail(v)}} }); export const Provider = mongoose.model('Provider', providerSchema); From 0a5b65d765d194b2dd43451bb15be1470e125990 Mon Sep 17 00:00:00 2001 From: pablogaraay Date: Mon, 19 May 2025 13:46:24 +0200 Subject: [PATCH 5/9] providers metadata added --- seeds/providers/providers.metadata.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 seeds/providers/providers.metadata.json diff --git a/seeds/providers/providers.metadata.json b/seeds/providers/providers.metadata.json new file mode 100644 index 0000000..cad1d5f --- /dev/null +++ b/seeds/providers/providers.metadata.json @@ -0,0 +1,12 @@ +{ + "indexes": [ + { + "v": {"numberInt": "2" }, + "key": { "_id": { "$numberInt": "1" } }, + "name": "_id_" + } + ], + "uuid": "0123456789abcdef0123456789abcdef", + "collectionName": "providers", + "type": "collection" +} \ No newline at end of file From 82b8b5a74ba532b4d044e5346390bda119fe493c Mon Sep 17 00:00:00 2001 From: pablogaraay Date: Mon, 19 May 2025 14:31:05 +0200 Subject: [PATCH 6/9] errors fixed --- package.json | 3 +-- seeds/providers/providers.metadata.json | 12 ------------ src/schemas/provider.ts | 3 +-- 3 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 seeds/providers/providers.metadata.json diff --git a/package.json b/package.json index f1ada60..2d120c6 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "dotenv": "^16.5.0", "express": "^4.21.2", "mongoose": "^8.15.0", - "ts-node": "^10.9.2", - "validator": "^13.15.0" + "ts-node": "^10.9.2" } } diff --git a/seeds/providers/providers.metadata.json b/seeds/providers/providers.metadata.json deleted file mode 100644 index cad1d5f..0000000 --- a/seeds/providers/providers.metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "indexes": [ - { - "v": {"numberInt": "2" }, - "key": { "_id": { "$numberInt": "1" } }, - "name": "_id_" - } - ], - "uuid": "0123456789abcdef0123456789abcdef", - "collectionName": "providers", - "type": "collection" -} \ No newline at end of file diff --git a/src/schemas/provider.ts b/src/schemas/provider.ts index 4b3cf17..abc416a 100644 --- a/src/schemas/provider.ts +++ b/src/schemas/provider.ts @@ -1,10 +1,9 @@ import mongoose from "mongoose"; -import isEmail from 'validator/lib/isEmail'; const providerSchema = new mongoose.Schema({ _id: { type: String }, name: { type: String, required: true }, - contact_email: { type: String, required: true, validate: {validator: (v: string) => isEmail(v)}} + contact_email: { type: String, required: true} }); export const Provider = mongoose.model('Provider', providerSchema); From c274b1d75620449e02597fe9990cafe89901f48e Mon Sep 17 00:00:00 2001 From: khalidbelk Date: Tue, 20 May 2025 18:07:54 +0200 Subject: [PATCH 7/9] feat(providers): seed data on launch --- src/config/database.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/config/database.ts b/src/config/database.ts index dd11428..f1a5e34 100644 --- a/src/config/database.ts +++ b/src/config/database.ts @@ -4,11 +4,12 @@ import dotenv from 'dotenv'; import { Sneaker } from "../schemas/sneaker"; import { Currency } from "../schemas/currency"; import { Store } from "../schemas/store"; - +import { Provider } from "../schemas/provider"; import sneakerSeedData from "../../seeds/sneakers/sneakers.json"; import currencySeedData from "../../seeds/currencies.json"; import storeSeedData from "../../seeds/stores/stores.json"; +import providerSeedData from "../../seeds/providers/providers.json"; dotenv.config({ path: '../../.env' }); @@ -29,7 +30,8 @@ export async function seedDatabase() { await Promise.all([ seedSneakers(), seedCurrencies(), - seedStores() + seedStores(), + seedProviders() ]); } catch (error) { console.error("Seeding failed:", error); @@ -72,3 +74,15 @@ async function seedStores() { await Store.insertMany(storeSeedData); console.log(`Seeded ${storeSeedData.length} documents in 'stores'`); } + +async function seedProviders() { + const providersCount = await Provider.countDocuments(); + + if (providersCount > 0) { + console.log(`Found ${providersCount} documents in 'providers' - skipping seed`); + return; + } + + await Provider.insertMany(providerSeedData); + console.log(`Seeded ${providerSeedData.length} documents in 'providers'`); +} From f5361738ad8bd9862b08673e2f1380d7f15860c0 Mon Sep 17 00:00:00 2001 From: khalidbelk Date: Tue, 20 May 2025 18:09:29 +0200 Subject: [PATCH 8/9] fix(providers): remove _id from mongoose schema fields --- src/schemas/provider.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/schemas/provider.ts b/src/schemas/provider.ts index abc416a..162f80a 100644 --- a/src/schemas/provider.ts +++ b/src/schemas/provider.ts @@ -1,7 +1,6 @@ import mongoose from "mongoose"; const providerSchema = new mongoose.Schema({ - _id: { type: String }, name: { type: String, required: true }, contact_email: { type: String, required: true} }); From 31c1da933531f3e9d3707ca949edf4eee67a428f Mon Sep 17 00:00:00 2001 From: khalidbelk Date: Tue, 20 May 2025 18:09:57 +0200 Subject: [PATCH 9/9] feat(providers): add missing responsse on updateProviderById controller --- src/controllers/provider.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/controllers/provider.ts b/src/controllers/provider.ts index c544428..bbd3283 100644 --- a/src/controllers/provider.ts +++ b/src/controllers/provider.ts @@ -94,6 +94,13 @@ export const updateProviderById = async (req, res) => { }); } + if (!updateData.name || !updateData.contact_email) { + return res.status(400).json({ + message: 'Invalid input data', + status: 'failure' + }); + } + return res.status(200).json({ items: provider, message: 'Provider updated successfully',