mirror of
https://github.com/Pythagora-io/gpt-pilot.git
synced 2026-01-09 21:27:53 -05:00
Enable user to choose if they want auth or not
This commit is contained in:
@@ -8,7 +8,6 @@ from core.config import FRONTEND_AGENT_NAME
|
||||
from core.llm.parser import DescriptiveCodeBlockParser
|
||||
from core.log import get_logger
|
||||
from core.telemetry import telemetry
|
||||
from core.templates.base import NoOptions
|
||||
from core.templates.registry import PROJECT_TEMPLATES
|
||||
|
||||
log = get_logger(__name__)
|
||||
@@ -44,6 +43,20 @@ class Frontend(FileDiffMixin, BaseAgent):
|
||||
)
|
||||
description = description.text.strip()
|
||||
|
||||
auth_needed = await self.ask_question(
|
||||
"Do you need authentication in your app (login, register, etc.)?",
|
||||
buttons={
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
},
|
||||
buttons_only=True,
|
||||
default="no",
|
||||
)
|
||||
options = {
|
||||
"auth": auth_needed.button == "yes",
|
||||
}
|
||||
self.state_manager.user_options = options
|
||||
|
||||
await self.send_message("Setting up project...")
|
||||
|
||||
self.next_state.epics = [
|
||||
@@ -58,7 +71,7 @@ class Frontend(FileDiffMixin, BaseAgent):
|
||||
}
|
||||
]
|
||||
|
||||
await self.apply_template()
|
||||
await self.apply_template(options)
|
||||
|
||||
return False
|
||||
|
||||
@@ -240,7 +253,7 @@ class Frontend(FileDiffMixin, BaseAgent):
|
||||
|
||||
return AgentResponse.done(self)
|
||||
|
||||
async def apply_template(self):
|
||||
async def apply_template(self, options: dict = {}):
|
||||
"""
|
||||
Applies a template to the frontend.
|
||||
"""
|
||||
@@ -251,7 +264,7 @@ class Frontend(FileDiffMixin, BaseAgent):
|
||||
return
|
||||
|
||||
template = template_class(
|
||||
NoOptions(),
|
||||
options,
|
||||
self.state_manager,
|
||||
self.process_manager,
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ When thinking about the scope of a single task, here are the components that nee
|
||||
**IMPORTANT: order of tasks**
|
||||
The tasks you create **MUST** be in the order that they should be implemented. When CRUD operations need to be implemented, first implement the Create operation, then Read, Update, and Delete.
|
||||
|
||||
{% if state.has_frontend() and not state.is_feature() %}
|
||||
{% if state.has_frontend() and not state.is_feature() and state.user_options.auth %}
|
||||
**IMPORTANT**
|
||||
If you are working on the Epic #1 that needs to implement the authentication system. The first task **MUST** be to remove the mocked data for authentication (register and login). After that, add any custom authentication requirements like different roles, different user data, etc.
|
||||
{% endif %}
|
||||
|
||||
@@ -25,7 +25,7 @@ Before we go into the coding part, your job is to split the development process
|
||||
Now, based on the project details provided{% if task_type == 'feature' %} and new feature description{% endif %}, think epic by epic and create the entire development plan{% if task_type == 'feature' %} for new feature{% elif task_type == 'app' %}. {% if state.files %}Continue from the existing code listed above{% else %}Start from the project setup{% endif %} and specify each epic until the moment when the entire app should be fully working{% if state.files %}. IMPORTANT: You should not reimplement what's already done - just continue from the implementation already there.{% endif %}{% endif %}
|
||||
|
||||
IMPORTANT!
|
||||
Frontend is already built and you don't need to create epics for it. You only need to create epics for backend implementation and connect it to existing frontend. Keep in mind that some backend functionality is already implemented.{% if task_type == 'app' %} The first epic **MUST** be to implement the authentication system if it's required.{% endif %}
|
||||
Frontend is already built and you don't need to create epics for it. You only need to create epics for backend implementation and connect it to existing frontend. Keep in mind that some backend functionality is already implemented.{% if task_type == 'app' and state.user_options.auth %} The first epic **MUST** be to implement the authentication system if it's required.{% endif %}
|
||||
|
||||
Strictly follow these rules:
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class StateManager:
|
||||
self.blockDb = False
|
||||
self.git_available = False
|
||||
self.git_used = False
|
||||
self.user_options = {}
|
||||
|
||||
@asynccontextmanager
|
||||
async def db_blocker(self):
|
||||
|
||||
@@ -8,21 +8,21 @@ This app has 2 parts:
|
||||
* It is running on port 5173 and this port should be used for user testing when possible
|
||||
* All requests to the backend need to go to an endpoint that starts with `/api/` (e.g. `/api/companies`)
|
||||
* Implememented pages:
|
||||
* Home - home (index) page (`/`)
|
||||
* Home - home (index) page (`/`){% if options.auth %}
|
||||
* Login - login page (`/login/`) - on login, stores the auth tokens to `accessToken` and `refreshToken` variables in local storage
|
||||
* Register - register page (`/register/`) - on register, store **ONLY** the `accessToken` variable in local storage
|
||||
* Register - register page (`/register/`) - on register, store **ONLY** the `accessToken` variable in local storage{% endif %}
|
||||
|
||||
** #2 Backend **
|
||||
* Express-based server implementing REST API endpoints in `api/`
|
||||
* Has codebase inside "server/" folder
|
||||
* Backend is running on port 3000
|
||||
* MongoDB database support with Mongoose
|
||||
* MongoDB database support with Mongoose{% if options.auth %}
|
||||
* Token-based authentication (using bearer access and refresh tokens)
|
||||
* User authentication (email + password):
|
||||
* login/register API endpoints in `/server/routes/auth.js`
|
||||
* authorization middleware in `/server/routes/middleware/auth.js`
|
||||
* user management logic in `/server/routes/services/user.js`
|
||||
* User authentication is implemented and doesn't require any additional work
|
||||
* User authentication is implemented and doesn't require any additional work{% endif %}
|
||||
|
||||
|
||||
Concurrently is used to run both client and server together with a single command (`npm run start`).
|
||||
|
||||
@@ -129,6 +129,7 @@ class Renderer:
|
||||
continue
|
||||
|
||||
contents = self.render_template(tpl_location, context)
|
||||
retval[output_location] = contents
|
||||
if contents != "":
|
||||
retval[output_location] = contents
|
||||
|
||||
return retval
|
||||
|
||||
@@ -12,8 +12,10 @@ function App() {
|
||||
<ThemeProvider defaultTheme="light" storageKey="ui-theme">
|
||||
<Router>
|
||||
<Routes>
|
||||
{% if options.auth %}
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
{% endif %}
|
||||
<Route path="/" element={<ProtectedRoute> <Layout /> </ProtectedRoute>} />
|
||||
</Routes>
|
||||
</Router>
|
||||
|
||||
@@ -12,7 +12,7 @@ const api = axios.create({
|
||||
});
|
||||
|
||||
let accessToken: string | null = null;
|
||||
|
||||
{% if options.auth %}
|
||||
// Axios request interceptor: Attach access token to headers
|
||||
api.interceptors.request.use(
|
||||
(config: AxiosRequestConfig): AxiosRequestConfig => {
|
||||
@@ -62,6 +62,6 @@ api.interceptors.response.use(
|
||||
return Promise.reject(error); // Pass other errors through
|
||||
}
|
||||
);
|
||||
|
||||
{% endif %}
|
||||
|
||||
export default api;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
import api from './api';
|
||||
|
||||
// Description: Login user functionality
|
||||
@@ -40,3 +41,4 @@ export const logout = async () => {
|
||||
throw new Error(error?.response?.data?.message || error.message);
|
||||
}
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
{% raw %}
|
||||
import { Bell, LogOut } from "lucide-react"
|
||||
import { Bell{% if options.auth %}, LogOut{% endif %} } from "lucide-react"
|
||||
import { Button } from "./ui/button"
|
||||
import { ThemeToggle } from "./ui/theme-toggle"
|
||||
import { useAuth } from "@/contexts/AuthContext"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
|
||||
export function Header() {
|
||||
const { logout } = useAuth()
|
||||
export function Header() {{% if options.auth %}
|
||||
const { logout } = useAuth(){% endif %}
|
||||
const navigate = useNavigate()
|
||||
|
||||
{% if options.auth %}
|
||||
const handleLogout = () => {
|
||||
logout()
|
||||
navigate("/login")
|
||||
}
|
||||
}{% endif %}
|
||||
return (
|
||||
<header className="fixed top-0 z-50 w-full border-b bg-background/80 backdrop-blur-sm">
|
||||
<div className="flex h-16 items-center justify-between px-6">
|
||||
<div className="text-xl font-bold">Home</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<ThemeToggle />
|
||||
<ThemeToggle />{% if options.auth %}
|
||||
<Button variant="ghost" size="icon" onClick={handleLogout}>
|
||||
<LogOut className="h-5 w-5" />
|
||||
</Button>
|
||||
</Button>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
{% raw %}
|
||||
import { createContext, useContext, useState, ReactNode } from "react";
|
||||
import { login as apiLogin, register as apiRegister } from "@/api/auth";
|
||||
@@ -66,3 +67,4 @@ export function useAuth() {
|
||||
return context;
|
||||
}
|
||||
{% endraw %}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
import { useState } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
@@ -100,3 +101,4 @@ export function Login() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
import { useState } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
@@ -101,3 +102,4 @@ export function Register() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const { validatePassword, isPasswordHash } = require('../utils/password.js');
|
||||
@@ -52,3 +53,4 @@ schema.set('toJSON', {
|
||||
const User = mongoose.model('User', schema);
|
||||
|
||||
module.exports = User;
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const express = require('express');
|
||||
const UserService = require('../services/userService.js');
|
||||
const { requireUser } = require('./middleware/auth.js');
|
||||
@@ -124,3 +125,4 @@ router.get('/me', requireUser, async (req, res) => {
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const UserService = require('../../services/userService.js');
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
@@ -17,3 +18,4 @@ const requireUser = (req, res, next) => {
|
||||
module.exports = {
|
||||
requireUser,
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
@@ -5,7 +5,9 @@ const express = require("express");
|
||||
const session = require("express-session");
|
||||
const MongoStore = require('connect-mongo');
|
||||
const basicRoutes = require("./routes/index");
|
||||
{% if options.auth %}
|
||||
const authRoutes = require("./routes/authRoutes");
|
||||
{% endif %}
|
||||
const { connectDB } = require("./config/database");
|
||||
const cors = require("cors");
|
||||
|
||||
@@ -38,8 +40,10 @@ app.on("error", (error) => {
|
||||
|
||||
// Basic Routes
|
||||
app.use(basicRoutes);
|
||||
{% if options.auth %}
|
||||
// Authentication Routes
|
||||
app.use('/api/auth', authRoutes);
|
||||
{% endif %}
|
||||
|
||||
// If no routes handled the request, it's a 404
|
||||
app.use((req, res, next) => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const { randomUUID } = require('crypto');
|
||||
|
||||
const User = require('../models/User.js');
|
||||
@@ -104,3 +105,4 @@ class UserService {
|
||||
}
|
||||
|
||||
module.exports = UserService;
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
const generateAccessToken = (user) => {
|
||||
@@ -12,3 +13,4 @@ module.exports = {
|
||||
generateAccessToken,
|
||||
generateRefreshToken
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{% if options.auth %}
|
||||
const bcrypt = require('bcrypt');
|
||||
|
||||
/**
|
||||
@@ -42,3 +43,4 @@ module.exports = {
|
||||
validatePassword,
|
||||
isPasswordHash,
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user