├── vercel.json ├── routes └── storyRoutes.js ├── config └── db.js ├── package.json ├── .gitignore ├── models └── Story.js ├── server.js ├── LICENSE └── controllers └── storyController.js /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "server.js", 6 | "use": "@vercel/node" 7 | } 8 | ], 9 | "rewrites": [{ "source": "/(.*)", "destination": "server.js" }] 10 | } 11 | -------------------------------------------------------------------------------- /routes/storyRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const { 4 | getStories, 5 | addStory, 6 | updateStory, 7 | deleteStory, 8 | } = require('../controllers/storyController'); 9 | 10 | router.route('/').get(getStories).post(addStory); 11 | router.route('/:id').put(updateStory).delete(deleteStory); 12 | 13 | module.exports = router; 14 | -------------------------------------------------------------------------------- /config/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectDB = async () => { 4 | try { 5 | const conn = await mongoose.connect(process.env.MONGO_URI); 6 | console.log(`MongoDB Connected: ${conn.connection.host}`); 7 | } catch (error) { 8 | console.error(`Error: ${error.message}`); 9 | process.exit(1); // Exit process with failure 10 | } 11 | }; 12 | 13 | module.exports = connectDB; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ai-wallpapers-backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon server.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "type": "commonjs", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.4.7", 17 | "express": "^4.21.2", 18 | "mongoose": "^8.12.1", 19 | "nodemon": "^3.1.9" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # local environment variables 5 | .env 6 | .env.local 7 | .env.development 8 | .env.production 9 | .env.test 10 | 11 | # Logs 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | logs 16 | *.log 17 | 18 | # output 19 | /dist 20 | /build 21 | 22 | # coverage 23 | /coverage 24 | 25 | # optional npm cache 26 | .npm 27 | 28 | # misc 29 | .DS_Store 30 | *.pem 31 | 32 | # IDE or editor specific 33 | .vscode/ 34 | .idea/ 35 | *.swp 36 | *.swo 37 | 38 | # MongoDB dump files (optional) 39 | /dump 40 | 41 | # optional OS-specific files 42 | ._* 43 | -------------------------------------------------------------------------------- /models/Story.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const storySchema = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: true, 7 | }, 8 | link: { 9 | type: String, 10 | required: true, 11 | }, 12 | category: { 13 | type: String, 14 | required: true, 15 | }, 16 | thumbnail: { 17 | type: String, // URL for the thumbnail image 18 | required: false, // Optional, in case some stories don’t have thumbnails 19 | }, 20 | createdAt: { 21 | type: Date, 22 | default: Date.now, 23 | }, 24 | }); 25 | 26 | const Story = mongoose.model('Story', storySchema); 27 | 28 | module.exports = Story; 29 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const dotenv = require('dotenv'); 3 | const connectDB = require('./config/db'); 4 | const cors = require('cors'); 5 | const storyRoutes = require('./routes/storyRoutes'); 6 | 7 | // Load environment variables 8 | dotenv.config(); 9 | 10 | // Connect to MongoDB 11 | connectDB(); 12 | 13 | const app = express(); 14 | const PORT = process.env.PORT || 5000; 15 | 16 | // Middleware 17 | app.use(cors()); 18 | app.use(express.json()); 19 | 20 | // Routes 21 | app.use('/stories', storyRoutes); 22 | 23 | app.get('/', (req, res) => { 24 | res.send('API is running...'); 25 | }); 26 | 27 | // Start server 28 | app.listen(PORT, () => { 29 | console.log(`Server running on http://localhost:${PORT}`); 30 | }); 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 rohanmistry231 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /controllers/storyController.js: -------------------------------------------------------------------------------- 1 | const Story = require('../models/Story'); 2 | 3 | // @desc Get all stories 4 | // @route GET /api/stories 5 | // @access Public 6 | const getStories = async (req, res) => { 7 | try { 8 | const stories = await Story.find(); 9 | res.status(200).json(stories); 10 | } catch (error) { 11 | res.status(500).json({ message: error.message }); 12 | } 13 | }; 14 | 15 | // @desc Add new story or multiple stories 16 | // @route POST /api/stories 17 | // @access Public 18 | const addStory = async (req, res) => { 19 | const stories = Array.isArray(req.body) ? req.body : [req.body]; 20 | 21 | // Validate each story 22 | const invalidStories = stories.filter(story => !story.title || !story.link || !story.category); 23 | if (invalidStories.length > 0) { 24 | return res.status(400).json({ message: 'Please fill all required fields for each story' }); 25 | } 26 | 27 | try { 28 | const newStories = stories.map(story => ({ 29 | title: story.title, 30 | link: story.link, 31 | category: story.category, 32 | thumbnail: story.thumbnail || 'https://via.placeholder.com/150', // Default thumbnail if none provided 33 | })); 34 | 35 | const savedStories = await Story.insertMany(newStories); 36 | res.status(201).json(savedStories); 37 | } catch (error) { 38 | res.status(500).json({ message: error.message }); 39 | } 40 | }; 41 | 42 | // @desc Update a story 43 | // @route PUT /api/stories/:id 44 | // @access Public 45 | const updateStory = async (req, res) => { 46 | const { title, link, category, thumbnail } = req.body; 47 | 48 | try { 49 | const story = await Story.findById(req.params.id); 50 | 51 | if (!story) { 52 | return res.status(404).json({ message: 'Story not found' }); 53 | } 54 | 55 | story.title = title || story.title; 56 | story.link = link || story.link; 57 | story.category = category || story.category; 58 | story.thumbnail = thumbnail || story.thumbnail; 59 | 60 | const updatedStory = await story.save(); 61 | res.status(200).json(updatedStory); 62 | } catch (error) { 63 | res.status(500).json({ message: error.message }); 64 | } 65 | }; 66 | 67 | // @desc Delete a story 68 | // @route DELETE /api/stories/:id 69 | // @access Public 70 | const deleteStory = async (req, res) => { 71 | try { 72 | const story = await Story.findById(req.params.id); 73 | 74 | if (!story) { 75 | return res.status(404).json({ message: 'Story not found' }); 76 | } 77 | 78 | await story.deleteOne(); 79 | res.status(200).json({ message: 'Story removed' }); 80 | } catch (error) { 81 | res.status(500).json({ message: error.message }); 82 | } 83 | }; 84 | 85 | module.exports = { 86 | getStories, 87 | addStory, 88 | updateStory, 89 | deleteStory, 90 | }; 91 | --------------------------------------------------------------------------------