-
Unleash the power of simple, fast and secure websites.
-
Build simple, fast, and secure websites without worrying about technical expertise or maintenance.
-
-
+
>
);
};
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 4eb7b67..aba1a02 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -4,31 +4,31 @@
body {
margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
[data-theme="dark"] {
color: #fff;
background-color: #030414;
- transition: all .4s cubic-bezier(0.23, 1, 0.320, 1);
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}
.announce[data-theme="dark"] {
color: #fff;
background: transparent;
border: 1px solid rgb(52, 52, 85);
- transition: all .4s cubic-bezier(0.23, 1, 0.320, 1);
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}
.color[data-theme="dark"] {
color: #fff;
background: transparent;
- transition: all .4s cubic-bezier(0.23, 1, 0.320, 1);
-}
\ No newline at end of file
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
+}
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 26a2c71..06f1991 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -1,13 +1,11 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from "react";
+import ReactDOM from "react-dom/client";
+import "./index.css";
+import App from "./App";
+import reportWebVitals from "./reportWebVitals";
-const root = ReactDOM.createRoot(document.getElementById('root'));
-root.render(
-
-);
+const root = ReactDOM.createRoot(document.getElementById("root"));
+root.render(
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
diff --git a/frontend/src/pages/Dashboard/Dashboard.js b/frontend/src/pages/Dashboard/Dashboard.js
index 9824616..b16a499 100644
--- a/frontend/src/pages/Dashboard/Dashboard.js
+++ b/frontend/src/pages/Dashboard/Dashboard.js
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { Helmet } from "react-helmet";
import { useNavigate } from "react-router-dom";
-import Projects from "../../Components/Projects/Projects"
+import Projects from "../../Components/Projects/Projects";
const Dashboard = () => {
const [user, setUser] = useState(null);
@@ -9,27 +9,25 @@ const Dashboard = () => {
const navigate = useNavigate();
const validateAccessToken = async () => {
- const response = await fetch('https://api.github.com/user', {
- method: 'GET',
+ const response = await fetch("https://api.github.com/user", {
+ method: "GET",
headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
});
const json = await response.json();
if (!json.id) {
- localStorage.removeItem('access-token');
- navigate('/login');
- }
- else {
+ localStorage.removeItem("access-token");
+ navigate("/login");
+ } else {
setUser(json);
}
- }
+ };
useEffect(() => {
- if (!localStorage.getItem('access-token')) {
- navigate('/login');
- }
- else {
+ if (!localStorage.getItem("access-token")) {
+ navigate("/login");
+ } else {
validateAccessToken();
}
}, []);
@@ -38,14 +36,10 @@ const Dashboard = () => {
StaticStorm | Dashboard
-
+
-
);
};
diff --git a/frontend/src/pages/Deploying/Deploying.js b/frontend/src/pages/Deploying/Deploying.js
index 61ff9c7..0aa2054 100644
--- a/frontend/src/pages/Deploying/Deploying.js
+++ b/frontend/src/pages/Deploying/Deploying.js
@@ -1,6 +1,6 @@
import { Helmet } from "react-helmet";
import { useParams } from "react-router-dom";
-import Deploy from "../../Components/Deploy/Deploy"
+import Deploy from "../../Components/Deploy/Deploy";
const NewProject = () => {
const { id } = useParams();
@@ -9,14 +9,10 @@ const NewProject = () => {
StaticStorm | Deploying
-
+
-
);
};
diff --git a/frontend/src/pages/Home/Home.js b/frontend/src/pages/Home/Home.js
index c82cd0b..2db7c5d 100644
--- a/frontend/src/pages/Home/Home.js
+++ b/frontend/src/pages/Home/Home.js
@@ -1,16 +1,12 @@
import { Helmet } from "react-helmet";
-import Hero from "../../Components/Sections/Hero.js"
+import Hero from "../../Components/Sections/Hero.js";
const Home = () => {
-
return (
<>
StaticStorm | Home
-
+
>
diff --git a/frontend/src/pages/Login/Login.js b/frontend/src/pages/Login/Login.js
index 08981ee..1a9cfa6 100644
--- a/frontend/src/pages/Login/Login.js
+++ b/frontend/src/pages/Login/Login.js
@@ -7,20 +7,16 @@ const Login = () => {
const navigate = useNavigate();
useEffect(() => {
- if (localStorage.getItem('access-token')) {
- navigate('/dashboard');
+ if (localStorage.getItem("access-token")) {
+ navigate("/dashboard");
}
}, []);
-
return (
<>
StaticStorm | Login
-
+
>
diff --git a/frontend/src/pages/NewProject/NewProject.js b/frontend/src/pages/NewProject/NewProject.js
index bc73024..3ced793 100644
--- a/frontend/src/pages/NewProject/NewProject.js
+++ b/frontend/src/pages/NewProject/NewProject.js
@@ -11,78 +11,83 @@ const NewProject = () => {
const getProjectsFirstTime = async () => {
const response = await fetch(`https://api.github.com/user/repos?page=1`, {
- method: 'GET',
+ method: "GET",
headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
});
const json = await response.json();
// console.log(json);
setProjects(json);
- }
+ };
const validateAccessToken = async () => {
- const response = await fetch('https://api.github.com/user', {
- method: 'GET',
+ const response = await fetch("https://api.github.com/user", {
+ method: "GET",
headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
});
const json = await response.json();
if (!json.id) {
- localStorage.removeItem('access-token');
- navigate('/login');
+ localStorage.removeItem("access-token");
+ navigate("/login");
}
- }
+ };
useEffect(() => {
- if (!localStorage.getItem('access-token')) {
- navigate('/login');
- }
- else {
+ if (!localStorage.getItem("access-token")) {
+ navigate("/login");
+ } else {
validateAccessToken();
getProjectsFirstTime();
}
}, []);
const getNextProjects = async () => {
- const response = await fetch(`https://api.github.com/user/repos?page=${nextPage}`, {
- method: 'GET',
- headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
- });
+ const response = await fetch(
+ `https://api.github.com/user/repos?page=${nextPage}`,
+ {
+ method: "GET",
+ headers: {
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
+ },
+ );
const json = await response.json();
console.log(json);
- setNextPage(page => page+1);
+ setNextPage((page) => page + 1);
setProjects(json);
- }
+ };
const getPreviousProjects = async () => {
- const response = await fetch(`https://api.github.com/user/repos?page=${nextPage-2}`, {
- method: 'GET',
- headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
- });
+ const response = await fetch(
+ `https://api.github.com/user/repos?page=${nextPage - 2}`,
+ {
+ method: "GET",
+ headers: {
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
+ },
+ );
const json = await response.json();
console.log(json);
- setNextPage(page => page-1);
+ setNextPage((page) => page - 1);
setProjects(json);
- }
-
-
+ };
return (
<>
StaticStorm | New Project
-
+
-
+
>
);
};
diff --git a/frontend/src/pages/SelectConfig/SelectConfig.js b/frontend/src/pages/SelectConfig/SelectConfig.js
index 3daf2df..73c8510 100644
--- a/frontend/src/pages/SelectConfig/SelectConfig.js
+++ b/frontend/src/pages/SelectConfig/SelectConfig.js
@@ -1,63 +1,55 @@
import { useEffect } from "react";
import { Helmet } from "react-helmet";
import { useNavigate, useParams } from "react-router-dom";
-import DeploySettings from "../../Components/DeploySettings/DeploySettings"
+import DeploySettings from "../../Components/DeploySettings/DeploySettings";
const SelectConfig = () => {
const navigate = useNavigate();
let { id } = useParams();
const validateAccessToken = async () => {
- const response = await fetch('https://api.github.com/user', {
- method: 'GET',
+ const response = await fetch("https://api.github.com/user", {
+ method: "GET",
headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
});
const json = await response.json();
if (!json.id) {
- localStorage.removeItem('access-token');
- navigate('/login');
+ localStorage.removeItem("access-token");
+ navigate("/login");
}
- }
+ };
-
const getRepoDetails = async () => {
const response = await fetch(`https://api.github.com/repositories/${id}`, {
- method: 'GET',
+ method: "GET",
headers: {
- 'Authorization': `Token ${localStorage.getItem('access-token')}`
- }
+ Authorization: `Token ${localStorage.getItem("access-token")}`,
+ },
});
const json = await response.json();
console.log(json);
- }
-
+ };
useEffect(() => {
- if (!localStorage.getItem('access-token')) {
- navigate('/login');
- }
- else {
+ if (!localStorage.getItem("access-token")) {
+ navigate("/login");
+ } else {
validateAccessToken();
getRepoDetails();
}
}, []);
-
return (
StaticStorm | New Project
-
+
-
);
};
diff --git a/frontend/src/reportWebVitals.js b/frontend/src/reportWebVitals.js
index 5253d3a..9ecd33f 100644
--- a/frontend/src/reportWebVitals.js
+++ b/frontend/src/reportWebVitals.js
@@ -1,6 +1,6 @@
-const reportWebVitals = onPerfEntry => {
+const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
- import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js
index 8f2609b..1dd407a 100644
--- a/frontend/src/setupTests.js
+++ b/frontend/src/setupTests.js
@@ -2,4 +2,4 @@
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
-import '@testing-library/jest-dom';
+import "@testing-library/jest-dom";
diff --git a/frontend/src/utils/VerifyLogin.js b/frontend/src/utils/VerifyLogin.js
index c1ea188..0ab1447 100644
--- a/frontend/src/utils/VerifyLogin.js
+++ b/frontend/src/utils/VerifyLogin.js
@@ -1,40 +1,39 @@
-import React from 'react'
-import { useNavigate, useSearchParams } from 'react-router-dom';
+import React from "react";
+import { useNavigate, useSearchParams } from "react-router-dom";
const VerifyLogin = () => {
- const navigate = useNavigate();
+ const navigate = useNavigate();
- const login = async () => {
- const response = await fetch('http://abcd.staticstorm.coderush.tech/api/auth', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ accessToken })
- });
-
- const json = await response.json();
- if (json.success) {
- navigate('/dashboard');
- }
- else {
- navigate('/login')
- }
- }
+ const login = async () => {
+ const response = await fetch(
+ "http://abcd.staticstorm.coderush.tech/api/auth",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ accessToken }),
+ },
+ );
- const [searchParams, setSearchParams] = useSearchParams();
- const accessToken = searchParams.get("access_token");
- if (!accessToken) {
- navigate('/login');
- }
- else {
- login();
- localStorage.setItem('access-token', accessToken);
+ const json = await response.json();
+ if (json.success) {
+ navigate("/dashboard");
+ } else {
+ navigate("/login");
}
+ };
+
+ const [searchParams, setSearchParams] = useSearchParams();
+ const accessToken = searchParams.get("access_token");
+ if (!accessToken) {
+ navigate("/login");
+ } else {
+ login();
+ localStorage.setItem("access-token", accessToken);
+ }
- return (
-
VerifyLogin
- )
-}
+ return
VerifyLogin
;
+};
-export default VerifyLogin
\ No newline at end of file
+export default VerifyLogin;
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
index 43c269b..6864a13 100644
--- a/frontend/tailwind.config.js
+++ b/frontend/tailwind.config.js
@@ -1,11 +1,9 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- content: [
- "./src/**/*.{js,jsx,ts,tsx}",
- ],
+ content: ["./src/**/*.{js,jsx,ts,tsx}"],
// adding the 'dark:' will change the theme
- darkMode: ['class', '[data-theme="dark"]'],
- corePlugins:{
- 'preflight': 'false',
- },
-}
\ No newline at end of file
+ darkMode: ["class", '[data-theme="dark"]'],
+ corePlugins: {
+ preflight: "false",
+ },
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..07d240d
--- /dev/null
+++ b/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "staticstorm",
+ "version": "0.8.0-beta",
+ "description": "Unleash the power of simple, fast and secure websites.",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "format": "prettier --check --ignore-path .gitignore .",
+ "format:fix": "prettier --write --ignore-path .gitignore ."
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/devarshishimpi/staticstorm.git"
+ },
+ "author": "Devarshi Shimpi",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/devarshishimpi/staticstorm/issues"
+ },
+ "homepage": "https://github.com/devarshishimpi/staticstorm#readme",
+ "devDependencies": {
+ "prettier": "3.0.3"
+ }
+}
diff --git a/server/db.js b/server/db.js
new file mode 100644
index 0000000..d1b21a0
--- /dev/null
+++ b/server/db.js
@@ -0,0 +1,13 @@
+require("dotenv").config();
+
+const mongoose = require("mongoose");
+
+const mongoURI = process.env.mongoURI;
+
+const connectToMongo = () => {
+ mongoose.connect(mongoURI, { dbName: "staticstorm" }, () => {
+ console.log("Connected To Mongo Successfully!!");
+ });
+};
+
+module.exports = connectToMongo;
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000..2b2c433
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,24 @@
+const express = require("express");
+const connectToMongo = require("./db");
+const cors = require("cors");
+
+connectToMongo();
+
+const app = express();
+app.use(express.json());
+app.use(cors());
+
+const PORT = process.env.PORT || 8181;
+
+app.get("/", (req, res) => {
+ res.send("Hi!!");
+});
+
+// Available Routes
+app.use("/api/auth", require("./routes/auth"));
+app.use("/api/deploy", require("./routes/deploy"));
+app.use("/api/projects", require("./routes/projects"));
+
+app.listen(PORT, () => {
+ console.log(`Server started at http://localhost:${PORT}`);
+});
diff --git a/server/models/Port.js b/server/models/Port.js
new file mode 100644
index 0000000..23f30c8
--- /dev/null
+++ b/server/models/Port.js
@@ -0,0 +1,14 @@
+const mongoose = require("mongoose");
+const { Schema } = require("mongoose");
+
+const PortSchema = new Schema(
+ {
+ nextFreePort: {
+ type: Number,
+ required: true,
+ },
+ },
+ { timestamps: true },
+);
+
+module.exports = mongoose.model("port", PortSchema);
diff --git a/server/models/Project.js b/server/models/Project.js
new file mode 100644
index 0000000..dc9a57a
--- /dev/null
+++ b/server/models/Project.js
@@ -0,0 +1,38 @@
+const mongoose = require("mongoose");
+const { Schema } = require("mongoose");
+
+const ProjectSchema = new Schema(
+ {
+ name: {
+ type: String,
+ required: true,
+ },
+ framework: {
+ type: String,
+ required: true,
+ },
+ rootDirectory: {
+ type: String,
+ required: true,
+ },
+ packageManager: {
+ type: String,
+ required: true,
+ },
+ githubRepoId: {
+ type: String,
+ required: true,
+ },
+ ownerId: {
+ type: String,
+ required: true,
+ },
+ port: {
+ type: Number,
+ required: true,
+ },
+ },
+ { timestamps: true },
+);
+
+module.exports = mongoose.model("project", ProjectSchema);
diff --git a/server/models/User.js b/server/models/User.js
new file mode 100644
index 0000000..afc4dfa
--- /dev/null
+++ b/server/models/User.js
@@ -0,0 +1,26 @@
+const mongoose = require("mongoose");
+const { Schema } = require("mongoose");
+
+const UserSchema = new Schema(
+ {
+ name: {
+ type: String,
+ required: true,
+ },
+ githubId: {
+ type: String,
+ required: true,
+ },
+ githubLogin: {
+ type: String,
+ },
+ projects: {
+ // An array of project ids of the user
+ type: Array,
+ default: [],
+ },
+ },
+ { timestamps: true },
+);
+
+module.exports = mongoose.model("user", UserSchema);
diff --git a/backend/package-lock.json b/server/package-lock.json
similarity index 100%
rename from backend/package-lock.json
rename to server/package-lock.json
diff --git a/backend/package.json b/server/package.json
similarity index 100%
rename from backend/package.json
rename to server/package.json
diff --git a/server/routes/auth.js b/server/routes/auth.js
new file mode 100644
index 0000000..30cd7ff
--- /dev/null
+++ b/server/routes/auth.js
@@ -0,0 +1,75 @@
+const express = require("express");
+const router = express.Router();
+const UserSchema = require("../models/User");
+// const { body, validationResult } = require('express-validator');
+var bcrypt = require("bcryptjs");
+var jwt = require("jsonwebtoken");
+// const fetchuser = require('../middleware/fetchuser');
+const axios = require("axios");
+const qs = require("querystring");
+require("dotenv").config();
+
+const JWT_SECRET = process.env.JWT_SECRET;
+
+router.post("/", async (req, res) => {
+ axios
+ .get("https://api.github.com/user", {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // res.json(response.data);
+ const theUser = await UserSchema.findOne({ githubId: response.data.id });
+ if (!theUser) {
+ // Create new account here!!
+ const newUser = await UserSchema.create({
+ name: response.data.name,
+ githubId: response.data.id,
+ githubLogin: response.data.login,
+ });
+
+ return res.status(200).json({ success: true });
+ } else {
+ // Logged in Successfully Here
+ return res.status(200).json({ success: true });
+ }
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.get("/github", (req, res) => {
+ const code = req.query.code;
+ const clientId = process.env.GITHUB_CLIENT_ID;
+ const clientSecret = process.env.GITHUB_CLIENT_SECRET;
+
+ axios
+ .post(
+ "https://github.com/login/oauth/access_token",
+ qs.stringify({
+ client_id: clientId,
+ client_secret: clientSecret,
+ code: code,
+ }),
+ {
+ headers: {
+ Accept: "application/json",
+ },
+ },
+ )
+ .then((response) => {
+ const accessToken = response.data.access_token;
+ return res.redirect(
+ `http://staticstorm.coderush.tech/verifyLogin?access_token=${accessToken}`,
+ );
+ })
+ .catch((error) => {
+ console.error(error);
+ res.send("An error occurred");
+ });
+});
+
+module.exports = router;
diff --git a/server/routes/deploy.js b/server/routes/deploy.js
new file mode 100644
index 0000000..b0b4ce9
--- /dev/null
+++ b/server/routes/deploy.js
@@ -0,0 +1,664 @@
+const express = require("express");
+const router = express.Router();
+const UserSchema = require("../models/User");
+const ProjectSchema = require("../models/Project");
+const PortSchema = require("../models/Port");
+// const { body, validationResult } = require('express-validator');
+var bcrypt = require("bcryptjs");
+var jwt = require("jsonwebtoken");
+// const fetchuser = require('../middleware/fetchuser');
+const axios = require("axios");
+const qs = require("querystring");
+const { spawn } = require("child_process");
+const { promises: fs } = require("fs");
+require("dotenv").config();
+
+const JWT_SECRET = process.env.JWT_SECRET;
+
+router.post("/", async (req, res) => {
+ const {
+ frameworkPreset,
+ rootDirectory,
+ subDomain,
+ packageManager,
+ githubRepoId,
+ } = req.body;
+
+ axios
+ .get("https://api.github.com/user", {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // res.json(response.data);
+ const theUser = await UserSchema.findOne({ githubId: response.data.id });
+ if (!theUser) {
+ return res
+ .status(400)
+ .json({ success: false, error: "User don't exist" });
+ } else {
+ const alreadyExist = await ProjectSchema.findOne({ name: subDomain });
+ if (alreadyExist)
+ return res.status(401).json({ error: "Domain Unavailable" });
+ const portArray = await PortSchema.find();
+ const port = portArray[0].nextFreePort;
+
+ const project = await ProjectSchema.create({
+ name: subDomain,
+ packageManager,
+ framework: frameworkPreset,
+ rootDirectory,
+ ownerId: theUser.githubId,
+ githubRepoId,
+ port,
+ });
+ return res.status(200).json({ success: true, projectId: project._id });
+ }
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+// router.post('/clone', async (req, res) => {
+// const theProject = await ProjectSchema.findById(req.body.projectId);
+// axios.get(
+// `https://api.github.com/repositories/${theProject.githubRepoId}`,
+// {
+// headers: {
+// 'Authorization': `Token ${req.body.accessToken}`
+// }
+// }
+// ).then(async response => {
+// // console.log(response.data);
+// process.chdir('/Users/devarshishimpi/Downloads/');
+
+// const gitClone = spawn('git', ['clone', `https://${req.body.accessToken}@github.com/${response.data.full_name}.git`]);
+
+// let logs = '';
+
+// gitClone.stdout.on('data', data => {
+// logs += data.toString();
+// });
+
+// gitClone.stderr.on('data', data => {
+// logs += data.toString();
+// });
+
+// gitClone.on('close', code => {
+// if (code === 0) {
+// return res.status(200).json({
+// logs,
+// message: 'Repository cloned successfully'
+// });
+// } else {
+// return res.status(500).json({
+// logs,
+// message: 'Failed to clone repository'
+// });
+// }
+// });
+// })
+// .catch(error => {
+// console.error(error);
+// res.json({ success: false });
+// });
+// });
+
+router.post("/clone", async (req, res) => {
+ if (req.body.projectId) {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ axios
+ .get(`https://api.github.com/repositories/${theProject.githubRepoId}`, {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // console.log(response.data);
+ const folderName = theProject.name; // name of the new folder
+ const path = "/projects"; // path to the parent directory of the new folder
+ const folderPath = `${path}/${folderName}`; // full path to the new folder
+ const mkdir = spawn("mkdir", [folderPath]); // create the new folder
+
+ mkdir.on("close", () => {
+ process.chdir(folderPath); // change the current working directory to the new folder
+ const gitClone = spawn("git", [
+ "clone",
+ `https://${req.body.accessToken}@github.com/${response.data.full_name}.git`,
+ ]);
+
+ let logs = "";
+
+ gitClone.stdout.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ gitClone.stderr.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ gitClone.on("close", (code) => {
+ if (code === 0) {
+ return res.status(200).json({
+ logs,
+ message: "Repository cloned successfully",
+ });
+ } else {
+ return res.status(500).json({
+ logs,
+ message: "Failed to clone repository",
+ });
+ }
+ });
+ });
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+ } else {
+ res.send("Internal server error!");
+ }
+});
+
+router.post("/install", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ axios
+ .get(`https://api.github.com/repositories/${theProject.githubRepoId}`, {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // console.log(response.data);
+ process.chdir(`/projects/${theProject.name}/${response.data.name}`);
+
+ const install = spawn("npm", [
+ "install",
+ "--legacy-peer-deps",
+ "-C",
+ theProject.rootDirectory,
+ ]);
+
+ let logs = "";
+
+ install.stdout.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ install.stderr.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ install.on("close", (code) => {
+ if (code === 0) {
+ return res.status(200).json({
+ logs,
+ message: "Dependencies installed successfully",
+ });
+ } else {
+ return res.status(500).json({
+ logs,
+ message: "Failed to install dependencies",
+ });
+ }
+ });
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.post("/build", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ axios
+ .get(`https://api.github.com/repositories/${theProject.githubRepoId}`, {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // console.log(response.data);
+ process.chdir(`/projects/${theProject.name}/${response.data.name}`);
+
+ const build = spawn("npm", [
+ "run",
+ "build",
+ "-C",
+ theProject.rootDirectory,
+ ]);
+
+ let logs = "";
+
+ build.stdout.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ build.stderr.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ build.on("close", (code) => {
+ if (code === 0) {
+ return res.status(200).json({
+ logs,
+ message: "Build successful",
+ });
+ } else {
+ return res.status(500).json({
+ logs,
+ message: "Build Failed",
+ });
+ }
+ });
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.post("/copybuild", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ axios
+ .get(`https://api.github.com/repositories/${theProject.githubRepoId}`, {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // console.log(response.data);
+ const folderName = theProject.name; // name of the new folder
+ const path = "/var/www/html"; // path to the parent directory of the new folder
+ const folderPath = `${path}/${folderName}`; // full path to the new folder
+ const mkdir = spawn("mkdir", [folderPath]); // create the new folder
+
+ mkdir.on("close", () => {
+ process.chdir(`/projects/${theProject.name}/${response.data.name}`); // change the current working directory to the new folder
+ process.chdir(theProject.rootDirectory); // change the current working directory to the new folder
+ const copyBuild = spawn("cp", ["-rf", "build", folderPath]);
+
+ let logs = "";
+
+ copyBuild.stdout.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ copyBuild.stderr.on("data", (data) => {
+ logs += data.toString();
+ });
+
+ copyBuild.on("close", (code) => {
+ if (code === 0) {
+ return res.status(200).json({
+ logs,
+ message: "Copied Successfully",
+ });
+ } else {
+ return res.status(500).json({
+ logs,
+ message: "Failed to copy",
+ });
+ }
+ });
+ });
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.post("/nginxconf", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ axios
+ .get(`https://api.github.com/repositories/${theProject.githubRepoId}`, {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ const nextFreePortArray = await PortSchema.find();
+ const nextFreePort = nextFreePortArray[0].nextFreePort;
+
+ const filePath = "/etc/nginx/sites-available/default";
+ const newServerBlock1 = `
+ server {
+ listen ${nextFreePort} default_server;
+ listen [::]:${nextFreePort} default_server;
+
+ root /var/www/html/${theProject.name}/build;
+
+ index index.html index.htm index.nginx-debian.html;
+
+ server_name ${theProject.name}.staticstorm.coderush.tech;
+
+ location / {
+ try_files $uri $uri/ /index.html;
+ }
+ }
+ `;
+ const newServerBlock2 = `
+ server {
+ listen 80;
+ server_name ${theProject.name}.staticstorm.coderush.tech;
+
+ location / {
+ proxy_pass http://localhost:${nextFreePort};
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ }
+ }
+ `;
+
+ fs.readFile(filePath, "utf-8")
+ .then((data) => {
+ const newData = data + newServerBlock1 + newServerBlock2;
+ return fs.writeFile(filePath, newData, "utf-8");
+ })
+ .then(() => {
+ console.log("File updated!");
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+
+ const updatePort = await PortSchema.updateOne(
+ { nextFreePort: nextFreePort },
+ { nextFreePort: nextFreePort + 1 },
+ );
+
+ res.json({ success: true });
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.post("/deleteconf", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ const nginxConfigPath = "/etc/nginx/sites-available/default";
+ const projectToRemove = `${theProject.name}.staticstorm.coderush.tech`;
+
+ try {
+ // Read the content of the nginx configuration file
+ let nginxConfig = await fs.readFile(nginxConfigPath, "utf-8");
+ // console.log(`Read nginx config: ${nginxConfig}`);
+
+ // Find the two server blocks corresponding to the project to remove
+ const serverBlockRegex = new RegExp(
+ `\\s*server {\\s*listen 80;\\s*server_name ${projectToRemove};\\s*location / {\\s*proxy_pass http://localhost:${theProject.port};[^}]*}\\s*}`,
+ "g",
+ );
+ const matches = nginxConfig.match(serverBlockRegex) || [];
+ console.log(`Found ${matches.length} matches: ${matches}`);
+
+ const serverBlocksToRemove = matches.join("");
+
+ // Remove the server blocks from the nginx configuration file content
+ nginxConfig = nginxConfig.replace(serverBlocksToRemove, "");
+ // console.log(`Modified nginx config: ${nginxConfig}`);
+
+ // Write the modified content back to the nginx configuration file
+ await fs.writeFile(nginxConfigPath, nginxConfig);
+ // console.log(`Wrote modified nginx config to ${nginxConfigPath}`);
+
+ console.log(
+ `Removed server blocks for project "${projectToRemove}" from nginx config.`,
+ );
+ } catch (err) {
+ console.error(
+ `Error removing project "${projectToRemove}" from nginx config: ${err}`,
+ );
+ return res.json({ success: false, err });
+ }
+
+ try {
+ // Read the content of the nginx configuration file
+ let nginxConfig = await fs.readFile(nginxConfigPath, "utf-8");
+
+ // Find the server block corresponding to the project to remove
+ const serverBlockRegex = new RegExp(
+ `\\s*server {\\s*listen ${theProject.port} default_server;\\s*listen \\[::\\]:${theProject.port} default_server;\\s*root /var/www/html/${theProject.name}/build;\\s*index index.html index.htm index.nginx-debian.html;\\s*server_name ${projectToRemove};\\s*location / {\\s*try_files \\$uri \\$uri/ /index.html;\\s*}\\s*}`,
+ "g",
+ );
+ const matches = nginxConfig.match(serverBlockRegex) || [];
+
+ // Remove the server block from the nginx configuration file content
+ const serverBlockToRemove = matches.join("");
+ nginxConfig = nginxConfig.replace(serverBlockToRemove, "");
+
+ // Write the modified content back to the nginx configuration file
+ await fs.writeFile(nginxConfigPath, nginxConfig);
+
+ console.log(
+ `Removed server block for project "${projectToRemove}" from nginx config.`,
+ );
+
+ return res.json({ success: true });
+ } catch (err) {
+ console.error(
+ `Error removing project "${projectToRemove}" from nginx config: ${err}`,
+ );
+ return res.json({ success: false, err });
+ }
+});
+
+router.post("/deleteproject", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+
+ await fs.rmdir(`/projects/${theProject.name}`, { recursive: true });
+ await fs.rmdir(`/var/www/html/${theProject.name}`, { recursive: true });
+
+ if (theProject) {
+ await theProject.delete();
+ return res.json({ success: true });
+ }
+ res.json({ success: false });
+});
+
+router.post("/configurewebhook", async (req, res) => {
+ const theProject = await ProjectSchema.findById(req.body.projectId);
+ const theUser = await UserSchema.findOne({ githubId: theProject.ownerId });
+ // Define the repository owner, repository name, and access token
+ const owner = theUser.githubLogin;
+ const repoId = theProject.githubRepoId;
+ const accessToken = req.body.accessToken;
+
+ // Make the HTTP request to get the repository information
+ axios
+ .get(`https://api.github.com/repositories/${repoId}`, {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "User-Agent": "axios",
+ },
+ })
+ .then((response) => {
+ const repoName = response.data.name;
+
+ // Define the payload for the webhook creation request
+ const payload = {
+ name: "web",
+ config: {
+ url: "http://abcd.staticstorm.coderush.tech/api/deploy/triggerwebhook",
+ content_type: "json",
+ },
+ events: ["push"],
+ active: true,
+ };
+
+ // Make the HTTP request to create the webhook
+ axios
+ .post(
+ `https://api.github.com/repos/${owner}/${repoName}/hooks`,
+ payload,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${accessToken}`,
+ "User-Agent": "axios",
+ },
+ },
+ )
+ .then((response) => {
+ console.log(`Webhook created: ${response.data.url}`);
+ res.json({ success: true });
+ })
+ .catch((error) => {
+ console.error(`Error creating webhook: ${error}`);
+ res.json({ success: false });
+ });
+ })
+ .catch((error) => {
+ console.error(`Error getting repository information: ${error}`);
+ res.json({ success: false });
+ });
+});
+
+router.post("/triggerwebhook", async (req, res) => {
+ // Retrieve the payload data from the request body
+ const payload = req.body;
+ console.log(`Received webhook for ${payload.repository.full_name}`);
+
+ const theProject = await ProjectSchema.findOne({
+ githubRepoId: payload.repository.id,
+ });
+
+ process.chdir(`/projects/${theProject.name}/${payload.repository.name}`);
+
+ const pull = spawn("git", ["pull"]);
+
+ let logs1 = "";
+
+ pull.stdout.on("data", (data) => {
+ logs1 += data.toString();
+ });
+
+ pull.stderr.on("data", (data) => {
+ logs1 += data.toString();
+ });
+
+ pull.on("close", (code) => {
+ console.log(logs1);
+ if (code === 0) {
+ process.chdir(`/projects/${theProject.name}/${payload.repository.name}`);
+
+ const install = spawn("npm", [
+ "install",
+ "--legacy-peer-deps",
+ "-C",
+ theProject.rootDirectory,
+ ]);
+
+ let logs2 = "";
+
+ install.stdout.on("data", (data) => {
+ logs2 += data.toString();
+ });
+
+ install.stderr.on("data", (data) => {
+ logs2 += data.toString();
+ });
+
+ install.on("close", (code) => {
+ console.log(logs2);
+ if (code === 0) {
+ process.chdir(
+ `/projects/${theProject.name}/${payload.repository.name}`,
+ );
+
+ const build = spawn("npm", [
+ "run",
+ "build",
+ "-C",
+ theProject.rootDirectory,
+ ]);
+
+ let logs4 = "";
+
+ build.stdout.on("data", (data) => {
+ logs4 += data.toString();
+ });
+
+ build.stderr.on("data", (data) => {
+ logs4 += data.toString();
+ });
+
+ build.on("close", (code) => {
+ console.log(logs4);
+ if (code === 0) {
+ const folderName = theProject.name; // name of the new folder
+ const path = "/var/www/html"; // path to the parent directory of the new folder
+ const folderPath = `${path}/${folderName}`; // full path to the new folder
+ const mkdir = spawn("mkdir", [folderPath]); // create the new folder
+
+ mkdir.on("close", () => {
+ process.chdir(
+ `/projects/${theProject.name}/${payload.repository.name}`,
+ ); // change the current working directory to the new folder
+ process.chdir(theProject.rootDirectory); // change the current working directory to the new folder
+ const copyBuild = spawn("cp", ["-rf", "build", folderPath]);
+
+ let logs3 = "";
+
+ copyBuild.stdout.on("data", (data) => {
+ logs3 += data.toString();
+ });
+
+ copyBuild.stderr.on("data", (data) => {
+ logs3 += data.toString();
+ });
+
+ copyBuild.on("close", (code) => {
+ if (code === 0) {
+ console.log(logs3);
+
+ return res.status(200).json({
+ logs3,
+ message: "Copied Successfully",
+ });
+ } else {
+ return res.status(500).json({
+ logs3,
+ message: "Failed to copy",
+ });
+ }
+ });
+ });
+ } else {
+ return res.status(500).json({
+ logs4,
+ message: "Build Failed",
+ });
+ }
+ });
+ } else {
+ return res.status(500).json({
+ logs2,
+ message: "Failed to install dependencies",
+ });
+ }
+ });
+ } else {
+ console.log(logs1);
+ return res.status(500).json({
+ logs1,
+ message: "Failed to pull new code",
+ });
+ }
+ });
+});
+
+router.post("/reloadnginx", async (req, res) => {
+ const reload = spawn("systemctl", ["restart", "nginx"]);
+
+ res.status(200).json({ success: true });
+});
+
+module.exports = router;
diff --git a/server/routes/projects.js b/server/routes/projects.js
new file mode 100644
index 0000000..30829bb
--- /dev/null
+++ b/server/routes/projects.js
@@ -0,0 +1,40 @@
+const express = require("express");
+const router = express.Router();
+const UserSchema = require("../models/User");
+const ProjectSchema = require("../models/Project");
+// const { body, validationResult } = require('express-validator');
+const axios = require("axios");
+
+// Get All Projects
+router.post("/", async (req, res) => {
+ axios
+ .get("https://api.github.com/user", {
+ headers: {
+ Authorization: `Token ${req.body.accessToken}`,
+ },
+ })
+ .then(async (response) => {
+ // res.json(response.data);
+ const allProjects = await ProjectSchema.find({
+ ownerId: response.data.id,
+ });
+ return res.status(200).json(allProjects);
+ })
+ .catch((error) => {
+ console.error(error);
+ res.json({ success: false });
+ });
+});
+
+router.post("/delete", async (req, res) => {
+ res.json({ success: false });
+ //const theProject = await ProjectSchema.findById(req.body.projectId);
+
+ //if (theProject) {
+ // await theProject.delete();
+ // return res.json({ success: true });
+ //}
+ //res.json({ success: false });
+});
+
+module.exports = router;