diff --git a/helpers/utils.js b/helpers/utils.js new file mode 100644 index 0000000..e9e7c46 --- /dev/null +++ b/helpers/utils.js @@ -0,0 +1,13 @@ +/** + * Utility functions for the application. + */ + +const isValidDomain = (domain) => { + // Regular expression to validate a domain name + const domainRegex = /^(?!:\/\/)([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/; + return domainRegex.test(domain); +} + +module.exports = { + isValidDomain +}; diff --git a/models/SiteModel.js b/models/SiteModel.js index b5894b4..4875b4b 100644 --- a/models/SiteModel.js +++ b/models/SiteModel.js @@ -3,6 +3,7 @@ */ const { supabase } = require('../auth'); +const { isValidDomain } = require('../helpers/utils'); class SiteModel { @@ -16,11 +17,25 @@ class SiteModel { * * @returns {Promise} - The result of the insert operation. */ - async insert(name, domainName) { - const { error } = await supabase.from(siteModel.tableName).insert({ - name: name, + async insert(domainName) { + // validate inputs + if (!domainName) { + throw new Error('Name and domain name are required to insert a site.'); + } + + // validate domain name format + if (!isValidDomain(domainName)) { + throw new Error('Invalid domain name format.'); + } + + // check if the domain name already exists + if (await this.getByDomainName(domainName).then(data => data.length !== 0)) { + throw new Error('Domain name already exists.'); + } + + const { data, error } = await supabase.from(SiteModel.tableName).insert({ domain_name: domainName, - }); + }).select(); if (error) { console.error('Error inserting site:', error); @@ -64,6 +79,24 @@ class SiteModel { return data; } + /** + * Retrieves a site by its domain name. + * + * @param {string} domainName - The domain name of the site. + * + * @returns {Promise} - The site object. + */ + async getByDomainName(domainName) { + const { data, error } = await supabase.from(SiteModel.tableName).select('*').eq('domain_name', domainName); + + if (error) { + console.error('Error fetching site by domain name:', error); + throw error; + } + + return data; + } + } module.exports = SiteModel; \ No newline at end of file diff --git a/routes/sites.js b/routes/sites.js index 25db6db..7817f3c 100644 --- a/routes/sites.js +++ b/routes/sites.js @@ -21,8 +21,14 @@ router.get('/', async function(req, res, next) { */ router.get('/:id', async function(req, res, next) { const siteId = req.params.id; + let site = null; - const site = await siteModel.getById(siteId); + try { + site = await siteModel.getById(siteId); + } catch (error) { + console.error('Error fetching site by ID:', error); + return res.status(400).send('Error fetching site: ' + error.message); + } if (!site) { return res.status(404).send('Site not found'); @@ -31,22 +37,52 @@ router.get('/:id', async function(req, res, next) { } }); +/** + * GET site by domain name. + * + * Returns a specific site by its domain name in JSON format. + */ +router.get('/domain/:domain', async function(req, res, next) { + const domainName = req.params.domain; + let sites = null; + + try { + sites = await siteModel.getByDomainName(domainName); + } catch (error) { + console.error('Error fetching site by domain name:', error); + return res.status(400).send('Error fetching site: ' + error.message); + } + + console.log('Site found:', sites); + + if (!sites || sites.length === 0) { + return res.status(404).send('Site not found'); + } else { + res.json(sites[0]); // Return the first match + } +}); + /** * POST create a new site. * * Creates a new site with the provided domain name. * - * // TODO: Implement validation for domain name format - * // TODO: Implement error handling for duplicate domains * // TODO: Ability to add additional site properties (e.g., name, description) */ -router.post('/add/:domain', function(req, res, next) { - const domain = req.params.domain; - - const newSite = siteModel.insert(domain); +router.post('/add', async function(req, res, next) { + const domain = req.body.domain; + let newSite = null; + + // insert method passes a lot of validation errors to the caller + try { + newSite = await siteModel.insert(domain); + } catch (error) { + console.error('Error creating site:', error); + return res.status(400).send('Error creating site: ' + error.message); + } if (!newSite) { - return res.status(400).send('Error creating site'); + res.status(400).send('Error creating site'); } else { res.status(201).json(newSite); }