Skip to content

Commit

Permalink
2024-11-15 - feedback ext recip
Browse files Browse the repository at this point in the history
  • Loading branch information
Luch76 committed Nov 15, 2024
1 parent e9e04c5 commit af4f493
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 256 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
import io.micronaut.http.cookie.SameSite;
import io.micronaut.http.netty.cookies.NettyCookie;
import io.micronaut.scheduling.TaskExecutors;
import io.micronaut.scheduling.annotation.ExecuteOn;
import io.micronaut.security.annotation.Secured;
Expand All @@ -20,7 +22,9 @@
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

Expand All @@ -34,6 +38,7 @@ public class FeedbackRequestExternalRecipientController {
private final FeedbackRequestServices feedbackReqServices;
private final FeedbackExternalRecipientServices feedbackExternalRecipientServices;
private static final Logger LOG = LoggerFactory.getLogger(FeedbackRequestExternalRecipientController.class);
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder();

public FeedbackRequestExternalRecipientController(FeedbackRequestServices feedbackRequestServices, FeedbackExternalRecipientServices feedbackExternalRecipientServices) {
this.feedbackReqServices = feedbackRequestServices;
Expand Down Expand Up @@ -121,4 +126,20 @@ private FeedbackRequestResponseDTO feedbackRequestFromEntity(FeedbackRequest fee
return dto;
}



@Get("/csrf/cookie")
public HttpResponse <?> getCsrfToken() {
LOG.info("CsrfModelProcessor, getCsrfToken");
SecureRandom random = new SecureRandom();
byte[] randomBytes = new byte[24];
random.nextBytes(randomBytes);
String cookieValue = base64Encoder.encodeToString(randomBytes);

return HttpResponse.ok()
// set cookie
.cookie(new NettyCookie("_csrf", cookieValue).path("/").sameSite(SameSite.Strict)).body(cookieValue)
;
}

}
3 changes: 0 additions & 3 deletions web-ui-external-feedback/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,6 @@ function App() {
<AppContextProvider>
<ErrorBoundary FallbackComponent={ErrorFallback}>
<div>
<Menu>
<SchemeToggle />
</Menu>
<div className="App">
<Routes />
</div>
Expand Down
7 changes: 5 additions & 2 deletions web-ui-external-feedback/src/api/api.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { UPDATE_TOAST } from '../context/actions';
import qs from 'qs';

export const BASE_API_URL = import.meta.env.VITE_APP_API_URL
export const BASE_API_URL = (
import.meta.env.VITE_APP_API_URL
? import.meta.env.VITE_APP_API_URL
: 'http://localhost:8080';
: 'http://localhost:8080'
) + '/services/feedback/requests/external/recipients'
;

export const getAvatarURL = email =>
BASE_API_URL +
Expand Down
7 changes: 7 additions & 0 deletions web-ui-external-feedback/src/api/feedback.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ export const getFeedbackRequestById = async (id, cookie) => {
});
};

export const getFeedbackRequestByIdForExternalRecipient = async (id, cookie) => {
return resolve({
url: `/${id}`,
headers: { 'X-CSRF-Header': cookie, Accept: 'application/json' }
});
};

export const getAnswerByRequestAndQuestionId = async (
requestId,
questionId,
Expand Down
6 changes: 3 additions & 3 deletions web-ui-external-feedback/src/components/routes/Routes.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { useContext } from 'react';
import { Switch, Route } from 'react-router-dom';
import { AppContext } from '../../context/AppContext';
import FeedbackSubmitConfirmation from '../feedback_submit_confirmation/FeedbackSubmitConfirmation';
import FeedbackSubmitExternalRecipientPage from "../../pages/FeedbackSubmitExternalRecipientPage.jsx";


export default function Routes() {
const { state } = useContext(AppContext);

return (
<Switch>
<Route exact path="/externalFeedback/">
<FeedbackSubmitConfirmation />
<Route path="/externalFeedback/">
<FeedbackSubmitExternalRecipientPage />
</Route>
</Switch>
);
Expand Down
248 changes: 1 addition & 247 deletions web-ui-external-feedback/src/context/AppContext.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
import React, { useEffect, useReducer, useMemo } from 'react';
import { reducer, initialState } from './reducer';
import { getCheckins, getAllCheckinsForAdmin } from './thunks';
import {
MY_PROFILE_UPDATE,
SET_CSRF,
SET_ROLES,
SET_USER_ROLES,
UPDATE_GUILDS,
UPDATE_MEMBER_SKILLS,
UPDATE_MEMBER_PROFILES,
UPDATE_TERMINATED_MEMBERS,
UPDATE_SKILLS,
UPDATE_CERTIFICATIONS,
UPDATE_TEAMS,
UPDATE_PEOPLE_LOADING,
UPDATE_TEAMS_LOADING
} from './actions';
import {
getCurrentUser,
getAllMembers,
getAllTerminatedMembers
} from '../api/member';
import {
selectCanViewCheckinsPermission,
} from './selectors';
import { getAllRoles, getAllUserRoles } from '../api/roles';
import { getMemberSkills } from '../api/memberskill';
import { BASE_API_URL } from '../api/api';
import { getAllGuilds } from '../api/guild';
import { getSkills } from '../api/skill';
import { getAllTeams } from '../api/team';
import {getCertifications} from "../api/certification.js";
;

const AppContext = React.createContext();

Expand All @@ -50,26 +24,9 @@ const AppContextProvider = props => {
reducer,
props?.value?.state || initialState
);
const userProfile =
state && state.userProfile ? state.userProfile : undefined;
const memberProfile =
userProfile && userProfile.memberProfile
? userProfile.memberProfile
: undefined;

const id = memberProfile ? memberProfile.id : undefined;
const pdlId = memberProfile ? memberProfile.pdlId : undefined;
const {
csrf,
guilds,
teams,
memberSkills,
memberProfiles,
checkins,
skills,
certifications,
roles,
userRoles
} = state;
const url = `${BASE_API_URL}/csrf/cookie`;
useEffect(() => {
Expand All @@ -92,209 +49,6 @@ const AppContextProvider = props => {
getCsrf();
}, [csrf]);

useEffect(() => {
async function getGuilds() {
let res = await getAllGuilds(csrf);
let data =
res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
if (data) {
dispatch({ type: UPDATE_GUILDS, payload: data });
}
}
if (csrf && !guilds) {
getGuilds();
}
}, [csrf, guilds]);

useEffect(() => {
async function getTeams() {
let res = await getAllTeams(csrf);
let data =
res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
if (data) {
dispatch({ type: UPDATE_TEAMS, payload: data });
dispatch({ type: UPDATE_TEAMS_LOADING });
}
}
if (csrf && !teams) {
dispatch({ type: UPDATE_TEAMS_LOADING });
getTeams();
}
}, [csrf, teams, dispatch]);

useEffect(() => {
const updateUserProfile = async () => {
let res = await getCurrentUser(csrf);
let profile =
res.payload && res.payload.data && !res.error
? res.payload.data
: undefined;

if (profile) {
dispatch({ type: MY_PROFILE_UPDATE, payload: profile });
}
};
if (csrf && !userProfile) {
updateUserProfile();
}
}, [csrf, userProfile]);

useEffect(() => {
const getAllMemberSkills = async () => {
const res = await getMemberSkills(csrf);
const memberSkills =
res && res.payload && res.payload.data ? res.payload.data : null;
if (memberSkills) {
dispatch({ type: UPDATE_MEMBER_SKILLS, payload: memberSkills });
}
};
if (csrf && !memberSkills) {
getAllMemberSkills();
}
}, [csrf, memberSkills]);

useEffect(() => {
async function getMemberProfiles() {
let res = await getAllMembers(csrf);
let profiles =
res.payload && res.payload.data && !res.error
? res.payload.data
: undefined;

if (profiles) {
dispatch({ type: UPDATE_MEMBER_PROFILES, payload: profiles });
dispatch({ type: UPDATE_PEOPLE_LOADING, payload: false });
}
}
async function getTerminatedMembers() {
let res = await getAllTerminatedMembers(csrf);
let profiles =
res.payload && res.payload.data && !res.error
? res.payload.data
: undefined;

if (profiles) {
dispatch({ type: UPDATE_TERMINATED_MEMBERS, payload: profiles });
}
}
if (csrf && userProfile && !memberProfiles) {
dispatch({ type: UPDATE_PEOPLE_LOADING, payload: true });
getMemberProfiles();
if (userProfile.role?.includes('ADMIN')) {
getTerminatedMembers();
}
}
}, [csrf, userProfile, memberProfiles]);

useEffect(() => {
function getAllTheCheckins() {
if (
userProfile &&
userProfile.permissions?.some(p =>
p?.permission?.includes('CAN_VIEW_CHECKINS_REPORT')
) &&
id &&
csrf
) {
getAllCheckinsForAdmin(dispatch, csrf);
} else if (id && csrf && selectCanViewCheckinsPermission(state)) {
getCheckins(id, pdlId, dispatch, csrf);
}
}
if (csrf && !checkins) {
getAllTheCheckins();
}
}, [csrf, pdlId, id, userProfile, checkins]);

useEffect(() => {
const getAllSkills = async () => {
const res = await getSkills(csrf);
const data =
res &&
res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
if (data && data.length > 0) {
dispatch({ type: UPDATE_SKILLS, payload: data });
}
};
if (csrf && !skills) {
getAllSkills();
}
}, [csrf, skills]);

useEffect(() => {
const getAllCertifications = async () => {
const res = await getCertifications(csrf);
const data =
res &&
res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
if (data && data.length > 0) {
dispatch({ type: UPDATE_CERTIFICATIONS, payload: data });
}
};
if (csrf && !certifications) {
getAllCertifications();
}
}, [csrf, certifications]);

useEffect(() => {
const getRoles = async () => {
const res = await getAllRoles(csrf);
const data =
res &&
res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
if (data && Array.isArray(data) && data.length > 0) {
dispatch({ type: SET_ROLES, payload: data });
}
};
if (csrf && !roles) {
getRoles();
}
}, [csrf, roles]);

useEffect(() => {
const getUserRoles = async () => {
// make call to the API
let res = await getAllUserRoles(csrf);
return res.payload &&
res.payload.data &&
res.payload.status === 200 &&
!res.error
? res.payload.data
: null;
};

if (csrf && !userRoles) {
getUserRoles().then(userRoles => {
dispatch({ type: SET_USER_ROLES, payload: userRoles });
});
}
}, [csrf, userRoles]);

const value = useMemo(() => {
return { state, dispatch };
}, [state]);
Expand Down
Loading

0 comments on commit af4f493

Please sign in to comment.