From 972283a73bad9dd76b51b5da1e8c3dc9133f8968 Mon Sep 17 00:00:00 2001 From: Aditya-JOSH Date: Tue, 14 Oct 2025 14:15:38 +0530 Subject: [PATCH 1/2] Add: Implemented React Router and Axios integration, and added test components to verify the setup. --- client/package-lock.json | 202 +++++++++++++++++++++++----- client/package.json | 2 + client/postcss.config.js | 6 + client/src/App.js | 22 ++- client/src/components/Categories.js | 35 +++++ client/src/components/Login.js | 61 +++++++++ client/src/components/Signup.js | 91 +++++++++++++ client/src/index.css | 4 + client/src/index.js | 5 +- client/src/services/api.js | 11 ++ client/tailwind.config.js | 20 +++ config/initializers/cors.rb | 4 +- 12 files changed, 416 insertions(+), 47 deletions(-) create mode 100644 client/postcss.config.js create mode 100644 client/src/components/Categories.js create mode 100644 client/src/components/Login.js create mode 100644 client/src/components/Signup.js create mode 100644 client/src/services/api.js create mode 100644 client/tailwind.config.js diff --git a/client/package-lock.json b/client/package-lock.json index 7c278b0..3475387 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,9 +11,11 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.12.2", "lucide-react": "^0.544.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^7.9.4", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } @@ -5439,6 +5441,31 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -5948,6 +5975,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -7174,6 +7213,19 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -7336,12 +7388,9 @@ "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -7403,14 +7452,26 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -8492,9 +8553,9 @@ "integrity": "sha512-noqGuLw158+DuD9UPRKHpJ2hGxpFyDlYYrfM0mWt4XhT4n0lwzTLh70Tkdyy4kyTmyTT9Bv7bWAJqw7cgkEXDg==" }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -8827,15 +8888,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8857,6 +8923,18 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -8996,11 +9074,11 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9079,9 +9157,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -9104,9 +9182,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -12462,6 +12540,14 @@ "tmpl": "1.0.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", @@ -14709,6 +14795,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -15005,6 +15096,50 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz", + "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==", + "dependencies": { + "react-router": "7.9.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "engines": { + "node": ">=18" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -15825,6 +15960,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" + }, "node_modules/set-function-length": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", diff --git a/client/package.json b/client/package.json index 7418958..5b089fa 100644 --- a/client/package.json +++ b/client/package.json @@ -6,9 +6,11 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.12.2", "lucide-react": "^0.544.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^7.9.4", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/client/postcss.config.js b/client/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/client/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/client/src/App.js b/client/src/App.js index bfcedfd..87cd88b 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,24 +1,20 @@ -import logo from './logo.svg'; import './App.css'; import ThemeToggle from './components/ThemeToggle'; +import Categories from './components/Categories'; +import Login from './components/Login'; +import Signup from './components/Signup'; +import { Routes, Route } from 'react-router-dom'; function App() { return (
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - + + } /> + } /> + } /> +
diff --git a/client/src/components/Categories.js b/client/src/components/Categories.js new file mode 100644 index 0000000..be0522d --- /dev/null +++ b/client/src/components/Categories.js @@ -0,0 +1,35 @@ +import { useEffect, useState } from "react"; +import api from "../services/api"; + +function Categories() { + const [categories, setCategories] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + api.get("/api/v1/categories") + .then(res => { + setCategories(res.data.data || []); + setLoading(false); + }) + .catch(err => { + setError('Failed to load categories'); + setLoading(false); + console.error(err); + }); + }, []); + + if (loading) return

Loading categories...

; + if (error) return

{error}

; + + return ( +
+

Categories

+ {categories.map(({ id, attributes }) => ( +

{attributes.name}

+ ))} +
+ ); +} + +export default Categories; diff --git a/client/src/components/Login.js b/client/src/components/Login.js new file mode 100644 index 0000000..e0e93fe --- /dev/null +++ b/client/src/components/Login.js @@ -0,0 +1,61 @@ +import React, { useState } from "react"; +import api from "../services/api"; + +const Login = () => { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + + const handleSubmit = async (e) => { + e.preventDefault(); + setError(""); + try { + await api.post("/login", { user: { email, password } }); + alert("Login successful!"); + // Redirect or update UI here + } catch (err) { + setError("Invalid email or password"); + } + }; + + return ( +
+
+

Login

+ {error &&
{error}
} +
+ + setEmail(e.target.value)} + className="w-full px-3 py-2 border rounded focus:outline-none focus:ring" + required + autoFocus + /> +
+
+ + setPassword(e.target.value)} + className="w-full px-3 py-2 border rounded focus:outline-none focus:ring" + required + /> +
+ +
+
+ ); +}; + +export default Login; diff --git a/client/src/components/Signup.js b/client/src/components/Signup.js new file mode 100644 index 0000000..ab7f971 --- /dev/null +++ b/client/src/components/Signup.js @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import api from '../services/api'; + +const Signup = () => { + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [passwordConfirmation, setPasswordConfirmation] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(''); + + const handleSubmit = async e => { + e.preventDefault(); + setError(''); + setSuccess(''); + if (password !== passwordConfirmation) { + setError('Passwords do not match'); + return; + } + try { + const res = await api.post('/signup', { + user: { name, email, password, password_confirmation: passwordConfirmation } + }); + setSuccess('Signup successful! You can now log in.'); + } catch (err) { + setError('Signup failed. Please check your details.'); + } + }; + + return ( +
+
+

Signup

+ {error &&
{error}
} + {success &&
{success}
} +
+ + setName(e.target.value)} + required + autoFocus + /> +
+
+ + setEmail(e.target.value)} + required + /> +
+
+ + setPassword(e.target.value)} + required + /> +
+
+ + setPasswordConfirmation(e.target.value)} + required + /> +
+ +
+
+ ); +}; + +export default Signup; diff --git a/client/src/index.css b/client/src/index.css index e769e9c..50fabf6 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -1,3 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + .theme-transition * { transition: background-color 0.4s ease, color 0.4s ease; } diff --git a/client/src/index.js b/client/src/index.js index 1a099f2..58e06b9 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -4,12 +4,15 @@ import './index.css'; import App from './App'; import { ThemeProvider } from './components/ThemeProvider'; import reportWebVitals from './reportWebVitals'; +import { BrowserRouter } from "react-router-dom"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( - + + + ); diff --git a/client/src/services/api.js b/client/src/services/api.js new file mode 100644 index 0000000..45e12be --- /dev/null +++ b/client/src/services/api.js @@ -0,0 +1,11 @@ +import axios from 'axios'; + +const api = axios.create({ + baseURL: process.env.REACT_APP_API_URL, + headers: { + 'Content-Type': 'application/json' + }, + withCredentials: true +}); + +export default api; diff --git a/client/tailwind.config.js b/client/tailwind.config.js new file mode 100644 index 0000000..97718d5 --- /dev/null +++ b/client/tailwind.config.js @@ -0,0 +1,20 @@ +module.exports = { + darkMode: 'class', + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + "./public/index.html", + ], + theme: { + extend: { + colors: { + backgroundLight: "#fdf6e3", + backgroundDark: "#282c34", + textLight: "#000000", + textDark: "#ffffff", + toggleLight: "#282c34", + toggleDark: "#fdf6e3", + }, + }, + }, + plugins: [], +}; diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb index b90f541..cf2707d 100644 --- a/config/initializers/cors.rb +++ b/config/initializers/cors.rb @@ -8,10 +8,10 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins '*' - + resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head], - expose: ["Authorization"] + credentials: true end end From df3ac355b88a309788101802675aac83931f4d0d Mon Sep 17 00:00:00 2001 From: Aditya-JOSH Date: Wed, 15 Oct 2025 11:11:28 +0530 Subject: [PATCH 2/2] Fix: lint errors and secure CORS configuration --- Gemfile | 3 +++ Gemfile.lock | 36 ++++++++++++++++++++++++++++++++++++ bin/brakeman | 29 +++++++++++++++++++++++++++++ bin/bundle-audit | 29 +++++++++++++++++++++++++++++ bin/bundler-audit | 29 +++++++++++++++++++++++++++++ bin/rubocop | 29 +++++++++++++++++++++++++++++ config/initializers/cors.rb | 2 +- 7 files changed, 156 insertions(+), 1 deletion(-) create mode 100755 bin/brakeman create mode 100755 bin/bundle-audit create mode 100755 bin/bundler-audit create mode 100755 bin/rubocop diff --git a/Gemfile b/Gemfile index 693beae..cb6d3d4 100644 --- a/Gemfile +++ b/Gemfile @@ -34,6 +34,9 @@ group :development, :test do gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'factory_bot_rails' gem 'faker' + gem 'bundler-audit', require: false + gem 'brakeman', require: false + gem 'rubocop', require: false end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 9125fbd..680e231 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -65,11 +65,16 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) + ast (2.4.3) base64 (0.2.0) bcrypt (3.1.20) bootsnap (1.18.4) msgpack (~> 1.2) + brakeman (5.4.1) builder (3.3.0) + bundler-audit (0.9.2) + bundler (>= 1.2.0, < 3) + thor (~> 1.0) byebug (11.1.3) case_transform (0.2) activesupport @@ -109,6 +114,7 @@ GEM activesupport (>= 6.1) i18n (1.14.6) concurrent-ruby (~> 1.0) + json (2.15.1) jsonapi-renderer (0.2.2) jsonapi-serializer (2.2.0) activesupport (>= 4.2) @@ -126,6 +132,8 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -159,7 +167,12 @@ GEM nokogiri (1.15.6-x86_64-darwin) racc (~> 1.4) orm_adapter (0.5.0) + parallel (1.27.0) + parser (3.3.9.0) + ast (~> 2.4.1) + racc pg (1.5.8) + prism (1.5.2) puma (5.6.8) nio4r (~> 2.0) racc (1.8.1) @@ -196,10 +209,12 @@ GEM method_source rake (>= 12.2) thor (~> 1.0) + rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) + regexp_parser (2.11.3) responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) @@ -221,6 +236,21 @@ GEM rspec-mocks (~> 3.10) rspec-support (~> 3.10) rspec-support (3.13.1) + rubocop (1.81.1) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.47.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.47.1) + parser (>= 3.3.7.2) + prism (~> 1.4) + ruby-progressbar (1.13.0) shoulda-matchers (4.5.1) activesupport (>= 4.2.0) spring (4.2.1) @@ -235,6 +265,9 @@ GEM timeout (0.4.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) warden (1.2.9) rack (>= 2.0.9) warden-jwt_auth (0.10.0) @@ -255,6 +288,8 @@ DEPENDENCIES active_model_serializers (~> 0.10.12) bcrypt (~> 3.1.7) bootsnap (>= 1.4.4) + brakeman + bundler-audit byebug devise devise-jwt @@ -269,6 +304,7 @@ DEPENDENCIES rails (~> 6.1.3, >= 6.1.3.2) rspec-json_expectations rspec-rails (~> 5.0.0) + rubocop shoulda-matchers (~> 4.0) spring tzinfo-data diff --git a/bin/brakeman b/bin/brakeman new file mode 100755 index 0000000..4b79003 --- /dev/null +++ b/bin/brakeman @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'brakeman' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("brakeman", "brakeman") diff --git a/bin/bundle-audit b/bin/bundle-audit new file mode 100755 index 0000000..addea6f --- /dev/null +++ b/bin/bundle-audit @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundle-audit' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("bundler-audit", "bundle-audit") diff --git a/bin/bundler-audit b/bin/bundler-audit new file mode 100755 index 0000000..3971084 --- /dev/null +++ b/bin/bundler-audit @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'bundler-audit' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("bundler-audit", "bundler-audit") diff --git a/bin/rubocop b/bin/rubocop new file mode 100755 index 0000000..d0c4882 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb index cf2707d..4fe631f 100644 --- a/config/initializers/cors.rb +++ b/config/initializers/cors.rb @@ -7,7 +7,7 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do - origins '*' + origins 'http://localhost:3001' resource '*', headers: :any,