Skip to content

Commit

Permalink
admin login
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickz22 committed Oct 7, 2024
1 parent 7faf5f7 commit 303abfe
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 39 deletions.
16 changes: 9 additions & 7 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MainContent from "./components/MainContent";
import Login from "./pages/Login";
import Onboard from "./pages/Onboard";
import "./App.css";
import AdminLogin from "./pages/AdminLogin";

const AppRoutes = () => {
const navigate = useNavigate();
Expand All @@ -35,6 +36,7 @@ const AppRoutes = () => {
return (
<Routes>
<Route path="/" element={<Login />} />
<Route path="/admin-login" element={<AdminLogin />} />
<Route path="/onboard" element={<Onboard />} />
<Route
path="/app/*"
Expand All @@ -58,12 +60,12 @@ function App() {
fontWeight: "700",
lineHeight: "1.2",
},
"body1": {
body1: {
fontSize: "16px",
lineHeight: "1.78",
fontWeight: "400",
},
"body2": {
body2: {
fontSize: "18px",
lineHeight: "1.78",
fontWeight: "400",
Expand All @@ -76,19 +78,19 @@ function App() {
h1: {
fontWeight: "700",
fontSize: "54px",
lineHeight: "0.93"
lineHeight: "0.93",
},
h2: {
fontWeight: "500",
fontSize: "40px",
lineHeight: "1.78"
lineHeight: "1.78",
},
h3: {
fontWeight: "500",
fontSize: "32px",
lineHeight: "1.78"
}
}
lineHeight: "1.78",
},
},
});

return (
Expand Down
29 changes: 24 additions & 5 deletions client/src/components/Api/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ api.interceptors.response.use(
},
async (error) => {
if (error.response) {

if (error.response.data.message.toLowerCase().includes("session")) {
window.location.href = "/";
return Promise.reject(error.response.data);
Expand Down Expand Up @@ -142,7 +141,7 @@ export const getRefreshToken = async () => {
export const fetchProspectingActivities = async (period, filterIds = []) => {
const response = await api.post("/get_prospecting_activities_by_ids", {
period,
filterIds
filterIds,
});
return { ...response.data, statusCode: response.status };
};
Expand All @@ -155,12 +154,17 @@ export const fetchProspectingActivities = async (period, filterIds = []) => {
* @param {string} searchTerm - Search term
* @returns {Promise<ApiResponse>}
*/
export const getPaginatedProspectingActivities = async (filterIds = [], page = 0, rowsPerPage = 10, searchTerm = "") => {
export const getPaginatedProspectingActivities = async (
filterIds = [],
page = 0,
rowsPerPage = 10,
searchTerm = ""
) => {
const response = await api.post("/get_paginated_prospecting_activities", {
filterIds,
page,
rowsPerPage,
searchTerm
searchTerm,
});
return { ...response.data, statusCode: response.status };
};
Expand Down Expand Up @@ -414,4 +418,19 @@ export const pauseStripePaymentSchedule = async (userId, email) => {
email,
});
return { ...response.data, statusCode: response.status };
};
};

/**
* Performs an admin login with the given user ID
* @param {string} userId - The ID of the user to login as
* @returns {Promise<ApiResponse>}
*/
export const adminLogin = async (userId) => {
try {
const response = await api.post("/admin_login", { userId });
return { ...response.data, statusCode: response.status };
} catch (error) {
console.error("Error during admin login:", error);
throw error;
}
};
77 changes: 77 additions & 0 deletions client/src/pages/AdminLogin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from "react";
import { Button, Box, Container, Typography, TextField } from "@mui/material";
import logo from "../assets/images/logo.jpeg";
import { adminLogin } from "../components/Api/Api";

const AdminLogin = () => {
const [userId, setUserId] = useState("");
const [error, setError] = useState("");

const handleAdminLogin = async (e) => {
e.preventDefault();

if (!userId.trim()) {
setError("Please enter a User ID");
return;
}

try {
const response = await adminLogin(userId.trim());

if (response.success) {
// Store the session token
localStorage.setItem("sessionToken", response.session_token);
// Redirect to the main application page or dashboard
window.location.href = "/app/prospecting";
} else {
setError(response.error || "An error occurred during login");
}
} catch (error) {
console.error("Error during admin login:", error);
setError("An unexpected error occurred. Please try again.");
}
};

return (
<Container maxWidth="sm" sx={{ textAlign: "center", marginTop: "100px" }}>
<Box display="flex" flexDirection="column" alignItems="center">
<img
src={logo}
alt="InsideOutbound Logo"
style={{ marginBottom: "20px", width: "200px" }}
/>
<Typography variant="h4" gutterBottom>
Admin Login
</Typography>
<TextField
fullWidth
label="User ID to login as"
variant="outlined"
value={userId}
onChange={(e) => setUserId(e.target.value)}
sx={{ marginBottom: "20px" }}
/>
{error && (
<Typography color="error" sx={{ marginBottom: "20px" }}>
{error}
</Typography>
)}
<Button
variant="contained"
color="error"
onClick={handleAdminLogin}
sx={{
padding: "10px 20px",
fontSize: "16px",
display: "block",
width: "15rem",
}}
>
Login as Admin
</Button>
</Box>
</Container>
);
};

export default AdminLogin;
27 changes: 25 additions & 2 deletions client/src/pages/Login.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from "react";
import { Button, Box, Container } from "@mui/material";
import { useNavigate } from "react-router-dom";
import logo from "../assets/images/logo.jpeg";
import { generatePKCEChallenge } from "../utils/crypto";
import config from "../config";

const Login = () => {
const handleLogin = async (e, loginUrlBase) => {
const navigate = useNavigate();

const handleLogin = async (e, loginUrlBase, isAdmin = false) => {
e.preventDefault();

const { codeVerifier, codeChallenge } = await generatePKCEChallenge();
Expand All @@ -16,11 +19,12 @@ const Login = () => {
const clientId = config.clientId;
const redirectUri = `${config.apiBaseUrl}/oauth/callback`;

// Encode the code verifier and sandbox flag in the state parameter
// Encode the code verifier, sandbox flag, and admin flag in the state parameter
const state = encodeURIComponent(
JSON.stringify({
codeVerifier,
isSandbox,
isAdmin,
})
);

Expand All @@ -33,6 +37,9 @@ const Login = () => {
console.error("Error starting auth session:", error);
}
};

const showAdminLogin = process.env.REACT_APP_SHOW_ADMIN_LOGIN === "true";

return (
<Container maxWidth="sm" sx={{ textAlign: "center", marginTop: "100px" }}>
<Box display="flex" flexDirection="column" alignItems="center">
Expand Down Expand Up @@ -64,11 +71,27 @@ const Login = () => {
padding: "10px 20px",
fontSize: "16px",
display: "block",
marginBottom: "10px",
width: "15rem",
}}
>
Login to Sandbox
</Button>
{showAdminLogin && (
<Button
variant="contained"
color="error"
onClick={() => navigate("/admin-login")}
sx={{
padding: "10px 20px",
fontSize: "16px",
display: "block",
width: "15rem",
}}
>
Admin Login
</Button>
)}
</Box>
</Box>
</Container>
Expand Down
5 changes: 4 additions & 1 deletion server/app/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ class SettingsModel(SerializableModel):
skipOpportunityCriteria: Optional[FilterContainerModel] = None
userTimeZone: Optional[str] = None


class DataType(str, Enum):
STRING = "string"
NUMBER = "number"
Expand All @@ -376,6 +377,7 @@ class DataType(str, Enum):
SELECT = "select"
IMAGE = "image"


class SObjectFieldModel(SerializableModel):
type: str
name: str
Expand All @@ -395,7 +397,8 @@ class TokenData(SerializableModel):
id: str
token_type: str
issued_at: str



class SessionState(SerializableModel):
salesforce_id: str
access_token: str
Expand Down
46 changes: 44 additions & 2 deletions server/app/database/session_selector.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from app.database.supabase_connection import get_supabase_admin_client
from app.data_models import AuthenticationError

from app.data_models import AuthenticationError, ApiResponse
import json
from app.database.supabase_retry import retry_on_temporary_unavailable


@retry_on_temporary_unavailable()
def fetch_supabase_session(session_id: str):
try:
Expand All @@ -26,3 +27,44 @@ def fetch_supabase_session(session_id: str):
raise
# For any other exception, wrap it in an AuthenticationError
raise AuthenticationError(f"Error fetching session: {str(e)}")


def fetch_session_by_salesforce_id(salesforce_id: str) -> ApiResponse:
try:
supabase = get_supabase_admin_client()

# Query all sessions, ordered by expiry descending
response = supabase.table("Session").select("*").order("expiry", desc=True).execute()

if not response.data:
return ApiResponse(success=False, message="No sessions found")

# Filter sessions based on the salesforce_id in the state
matching_session = next(
(
session
for session in response.data
if json.loads(session["state"]).get("salesforce_id") == salesforce_id
),
None,
)

if matching_session:
# Extract the state dict
state_dict = json.loads(matching_session["state"])

# Extract the refresh_token
refresh_token = state_dict.get("refresh_token")

return ApiResponse(
success=True,
data=[{"session": matching_session, "refresh_token": refresh_token}],
)
else:
return ApiResponse(
success=False,
message=f"No session found for Salesforce ID: {salesforce_id}",
)

except Exception as e:
return ApiResponse(success=False, message=f"Error fetching session: {str(e)}")
Loading

0 comments on commit 303abfe

Please sign in to comment.