From acba915074ef5022c775b199622a80b90366322e Mon Sep 17 00:00:00 2001 From: Martin Hradil Date: Thu, 24 Oct 2024 15:28:18 +0000 Subject: [PATCH 1/3] wip: allow session login use /auth/login/ for cookies remove last AppContext.user, switch to UserContext.getUsername/isLoggedIn --- config/start.config.js | 1 + pulp-ui-config.json | 2 +- src/api/base.ts | 2 +- src/api/pulp.ts | 5 +++- src/app-context.tsx | 13 ++-------- src/components/delete-user-modal.tsx | 6 ++--- src/containers/ansible-remote/tab-access.tsx | 1 - .../ansible-repository/tab-access.tsx | 1 - src/containers/login/login.tsx | 11 ++++++++- src/layout.tsx | 8 +++---- src/menu.tsx | 6 ++--- src/user-context.tsx | 24 +++++++++++++++---- 12 files changed, 47 insertions(+), 33 deletions(-) diff --git a/config/start.config.js b/config/start.config.js index ea807fd..f395262 100644 --- a/config/start.config.js +++ b/config/start.config.js @@ -15,6 +15,7 @@ module.exports = webpackBase({ DEV_PROXY: { '/api/': proxyTarget, '/assets/': proxyTarget, + '/auth/': proxyTarget, '/extensions/': proxyTarget, '/pulp/': proxyTarget, '/static/rest_framework/': proxyTarget, diff --git a/pulp-ui-config.json b/pulp-ui-config.json index 3964aba..354e89d 100644 --- a/pulp-ui-config.json +++ b/pulp-ui-config.json @@ -1,6 +1,6 @@ { "API_BASE_PATH": "/pulp/api/v3/", "UI_BASE_PATH": "/ui/", - "UI_EXTERNAL_LOGIN_URI": null, + "UI_EXTERNAL_LOGIN_URI": "/auth/login/", "EXTRA_VERSION": "" } diff --git a/src/api/base.ts b/src/api/base.ts index 4c1bf79..316a885 100644 --- a/src/api/base.ts +++ b/src/api/base.ts @@ -10,7 +10,7 @@ export class BaseAPI { this.http = axios.create({ // adapter + withCredentials ensures no popup on http basic auth fail adapter: 'fetch', - withCredentials: false, + //withCredentials: false, // baseURL gets set in PulpAPI paramsSerializer: { diff --git a/src/api/pulp.ts b/src/api/pulp.ts index 05321eb..5e00fad 100644 --- a/src/api/pulp.ts +++ b/src/api/pulp.ts @@ -11,11 +11,14 @@ export class PulpAPI extends BaseAPI { this.http.interceptors.request.use((request) => { if (!request.auth) { - request.auth = JSON.parse( + const credentials = JSON.parse( window.sessionStorage.credentials || window.localStorage.credentials || '{}', ); + if (credentials?.username !== 'HACK') { + request.auth = credentials; + } } request.baseURL = config.API_BASE_PATH; diff --git a/src/app-context.tsx b/src/app-context.tsx index 9dd4424..352d23a 100644 --- a/src/app-context.tsx +++ b/src/app-context.tsx @@ -14,15 +14,15 @@ export interface IAppContextType { queueAlert: (alert: AlertType) => void; setAlerts: (alerts: AlertType[]) => void; settings; // deprecated - user; // deprecated } export const AppContext = createContext(undefined); export const useAppContext = () => useContext(AppContext); +// FIXME: rename to AlertContext*; deal with deprecated featureFlags & settings export const AppContextProvider = ({ children }: { children: ReactNode }) => { const [alerts, setAlerts] = useState([]); - const { credentials } = useUserContext(); + const { hasPermission } = useUserContext(); // hub compat for now const featureFlags = { @@ -43,7 +43,6 @@ export const AppContextProvider = ({ children }: { children: ReactNode }) => { }; const queueAlert = (alert) => setAlerts((alerts) => [...alerts, alert]); - const hasPermission = (_name) => true; // FIXME: permission handling return ( { queueAlert, setAlerts, settings, - // FIXME: hack - user: credentials - ? { - username: credentials.username, - groups: [], - model_permissions: {}, - } - : null, }} > {children} diff --git a/src/components/delete-user-modal.tsx b/src/components/delete-user-modal.tsx index 7374ef7..9ea8bfe 100644 --- a/src/components/delete-user-modal.tsx +++ b/src/components/delete-user-modal.tsx @@ -19,7 +19,7 @@ export const DeleteUserModal = ({ user, }: IProps) => { const [waiting, setWaiting] = useState(false); - const { credentials } = useUserContext(); + const { getUsername } = useUserContext(); if (!user || !isOpen) { return null; @@ -29,11 +29,11 @@ export const DeleteUserModal = ({ closeModal(false)} deleteAction={() => deleteUser()} - isDisabled={waiting || user.username === credentials.username} + isDisabled={waiting || user.username === getUsername()} spinner={waiting} title={t`Delete user?`} > - {user.username === credentials.username ? ( + {user.username === getUsername() ? ( t`Deleting yourself is not allowed.` ) : ( diff --git a/src/containers/ansible-remote/tab-access.tsx b/src/containers/ansible-remote/tab-access.tsx index 78fa8a6..a798f3a 100644 --- a/src/containers/ansible-remote/tab-access.tsx +++ b/src/containers/ansible-remote/tab-access.tsx @@ -28,7 +28,6 @@ interface TabProps { featureFlags; hasPermission; state: { params }; - user; }; } diff --git a/src/containers/ansible-repository/tab-access.tsx b/src/containers/ansible-repository/tab-access.tsx index 4f1d2ef..2fb4c58 100644 --- a/src/containers/ansible-repository/tab-access.tsx +++ b/src/containers/ansible-repository/tab-access.tsx @@ -28,7 +28,6 @@ interface TabProps { featureFlags; hasPermission; state: { params }; - user; }; } diff --git a/src/containers/login/login.tsx b/src/containers/login/login.tsx index b71ead8..c0870f1 100644 --- a/src/containers/login/login.tsx +++ b/src/containers/login/login.tsx @@ -14,7 +14,7 @@ function PulpLoginPage(_props) { const { setCredentials, clearCredentials } = useUserContext(); const { next } = useQueryParams(); - const [username, setUsername] = useState(''); + const [username, setUsername] = useState('HACK'); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [redirect, setRedirect] = useState(''); @@ -25,6 +25,15 @@ function PulpLoginPage(_props) { }, []); const onLoginClick = (e) => { + if (username === 'HACK') { + setCredentials(username, password, remember); + setRedirect( + next && next !== '/login/' ? next : formatPath(Paths.core.status), + ); + e?.preventDefault(); + return; + } + PulpLoginAPI.try(username, password) .then(() => { // verified, save diff --git a/src/layout.tsx b/src/layout.tsx index 7d6af8b..81dad0c 100644 --- a/src/layout.tsx +++ b/src/layout.tsx @@ -33,16 +33,14 @@ import { useUserContext } from './user-context'; export const StandaloneLayout = ({ children }: { children: ReactNode }) => { const [aboutModalVisible, setAboutModalVisible] = useState(false); - const { credentials, clearCredentials } = useUserContext(); + const { getUsername, clearCredentials } = useUserContext(); + const userName = getUsername(); let aboutModal = null; let docsDropdownItems = []; let userDropdownItems = []; - let userName: string; - - if (credentials) { - userName = credentials.username; + if (userName) { userDropdownItems = [ Username: {userName} diff --git a/src/menu.tsx b/src/menu.tsx index 37c54ca..50e98c2 100644 --- a/src/menu.tsx +++ b/src/menu.tsx @@ -28,7 +28,7 @@ const menuSection = (name, options = {}, items = []) => ({ const altPath = (p) => formatPath(p, {}, null, { ignoreMissing: true }); // condition: loggedIn OR condition: and(loggedIn, hasPlugin('rpm')) -const loggedIn = ({ user }) => !!user; +const loggedIn = ({ isLoggedIn }) => isLoggedIn(); const hasPlugin = (name) => ({ plugins }) => @@ -284,7 +284,7 @@ export const StandaloneMenu = () => { const location = useLocation(); const [menu, setMenu] = useState([]); - const { credentials } = useUserContext(); + const { isLoggedIn } = useUserContext(); const plugins = usePlugins(); @@ -312,7 +312,7 @@ export const StandaloneMenu = () => { diff --git a/src/user-context.tsx b/src/user-context.tsx index f87a4c0..333747d 100644 --- a/src/user-context.tsx +++ b/src/user-context.tsx @@ -7,15 +7,18 @@ import React, { } from 'react'; interface IUserContextType { + clearCredentials: () => void; credentials: { username: string; password: string; remember: boolean }; + getUsername: () => string; + hasPermission: (name: string) => boolean; + isLoggedIn: () => boolean; setCredentials: ( username: string, password: string, remember?: boolean, ) => void; - clearCredentials: () => void; - updateUsername: (username: string) => void; updatePassword: (password: string) => void; + updateUsername: (username: string) => void; } const UserContext = createContext(undefined); @@ -47,19 +50,30 @@ export const UserContextProvider = ({ children }: { children: ReactNode }) => { window.localStorage.removeItem('credentials'); window.sessionStorage.removeItem('credentials'); } + + // if (!credentials) { + // setCredentials({ username: 'HACK' }); + // } }, [credentials]); + const getUsername = () => credentials?.username; + const isLoggedIn = () => !!credentials?.username; + const hasPermission = (_name) => true; // FIXME: permission handling + return ( setCredentials(null), credentials, + getUsername, + hasPermission, + isLoggedIn, setCredentials: (username, password, remember = false) => setCredentials({ username, password, remember }), - clearCredentials: () => setCredentials(null), - updateUsername: (username) => - setCredentials((credentials) => ({ ...credentials, username })), updatePassword: (password) => setCredentials((credentials) => ({ ...credentials, password })), + updateUsername: (username) => + setCredentials((credentials) => ({ ...credentials, username })), }} > {children} From ee4f7b2729a3256ab12ebfc0004bf98208e46560 Mon Sep 17 00:00:00 2001 From: Martin Hradil Date: Mon, 28 Oct 2024 22:07:17 +0000 Subject: [PATCH 2/3] task detail - remove leading hr --- src/containers/task-management/task-detail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/task-management/task-detail.tsx b/src/containers/task-management/task-detail.tsx index b7866ff..f02dcd9 100644 --- a/src/containers/task-management/task-detail.tsx +++ b/src/containers/task-management/task-detail.tsx @@ -261,7 +261,7 @@ class TaskDetail extends Component { {resources.map((resource, index) => { return ( -
+ {index ?
: null} {t`Type`} From 638274748e995d9ff69491f6bf181244823c6c61 Mon Sep 17 00:00:00 2001 From: Martin Hradil Date: Mon, 28 Oct 2024 22:42:57 +0000 Subject: [PATCH 3/3] linters --- src/components/pulp-about-modal.tsx | 12 +-- src/layout.tsx | 128 +++++++++++++++------------- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/src/components/pulp-about-modal.tsx b/src/components/pulp-about-modal.tsx index f142d2d..daba0c2 100644 --- a/src/components/pulp-about-modal.tsx +++ b/src/components/pulp-about-modal.tsx @@ -26,14 +26,14 @@ const Value = ({ children }: { children: ReactNode }) => ( interface IProps { isOpen: boolean; onClose: () => void; - userName: string; + username: string; } interface IApplicationInfo { pulp_core_version?: string; } -export const PulpAboutModal = ({ isOpen, onClose, userName }: IProps) => { +export const PulpAboutModal = ({ isOpen, onClose, username }: IProps) => { const [applicationInfo, setApplicationInfo] = useState({}); useEffect(() => { @@ -54,7 +54,7 @@ export const PulpAboutModal = ({ isOpen, onClose, userName }: IProps) => { const ui_extra = config.EXTRA_VERSION; // FIXME - const user = { username: userName, id: null, groups: [] }; + const user = { username, id: null, groups: [] }; return ( { ? formatPath(Paths.core.user.detail, { user_id: user.id }) : null } - title={userName} + title={username} > - {userName} - {user?.username && user.username !== userName ? ( + {username} + {user?.username && user.username !== username ? ( <> ({user.username}) ) : null} diff --git a/src/layout.tsx b/src/layout.tsx index 81dad0c..f819512 100644 --- a/src/layout.tsx +++ b/src/layout.tsx @@ -31,38 +31,12 @@ import { StandaloneMenu } from './menu'; import { Paths, formatPath } from './paths'; import { useUserContext } from './user-context'; -export const StandaloneLayout = ({ children }: { children: ReactNode }) => { - const [aboutModalVisible, setAboutModalVisible] = useState(false); - const { getUsername, clearCredentials } = useUserContext(); - - const userName = getUsername(); - let aboutModal = null; - let docsDropdownItems = []; - let userDropdownItems = []; - - if (userName) { - userDropdownItems = [ - - Username: {userName} - , - , - {t`My profile`} - } - />, - - clearCredentials()} - > - {t`Logout`} - , - ]; - - docsDropdownItems = [ +const DocsDropdown = ({ showAbout }: { showAbout: () => void }) => ( + } + items={[ { >{t`Documentation`} } />, - setAboutModalVisible(true)}> + showAbout()}> {t`About`} , - ].filter(Boolean); + ]} + toggleType='icon' + /> +); - aboutModal = ( - setAboutModalVisible(false)} - userName={userName} - /> - ); - } +const UserDropdown = ({ + username, + clearCredentials, +}: { + username?: string; + clearCredentials: () => void; +}) => + username ? ( + + Username: {username} + , + , + {t`My profile`} + } + />, + clearCredentials()} + > + {t`Logout`} + , + ]} + toggleType='dropdown' + /> + ) : null; + +export const StandaloneLayout = ({ children }: { children: ReactNode }) => { + const [aboutModalVisible, setAboutModalVisible] = useState(false); + const { getUsername, clearCredentials } = useUserContext(); + + const username = getUsername(); const Header = ( @@ -103,7 +114,7 @@ export const StandaloneLayout = ({ children }: { children: ReactNode }) => { padding: '9px 0 0 4px', }} > - Pulp UI + {APPLICATION_NAME} @@ -111,25 +122,14 @@ export const StandaloneLayout = ({ children }: { children: ReactNode }) => { - {credentials ? ( - } - items={docsDropdownItems} - toggleType='icon' + setAboutModalVisible(true)} /> + {username ? ( + - ) : null} - {!credentials ? ( - ) : ( - + )} @@ -146,7 +146,13 @@ export const StandaloneLayout = ({ children }: { children: ReactNode }) => { return ( {children} - {aboutModalVisible && aboutModal} + {aboutModalVisible ? ( + setAboutModalVisible(false)} + username={username} + /> + ) : null} ); };