Skip to content

Commit af4f493

Browse files
committed
2024-11-15 - feedback ext recip
1 parent e9e04c5 commit af4f493

File tree

8 files changed

+198
-256
lines changed

8 files changed

+198
-256
lines changed

server/src/main/java/com/objectcomputing/checkins/services/feedback_request/FeedbackRequestExternalRecipientController.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import io.micronaut.http.HttpResponse;
99
import io.micronaut.http.MediaType;
1010
import io.micronaut.http.annotation.*;
11+
import io.micronaut.http.cookie.SameSite;
12+
import io.micronaut.http.netty.cookies.NettyCookie;
1113
import io.micronaut.scheduling.TaskExecutors;
1214
import io.micronaut.scheduling.annotation.ExecuteOn;
1315
import io.micronaut.security.annotation.Secured;
@@ -20,7 +22,9 @@
2022
import org.slf4j.LoggerFactory;
2123

2224
import java.net.URI;
25+
import java.security.SecureRandom;
2326
import java.time.LocalDate;
27+
import java.util.Base64;
2428
import java.util.List;
2529
import java.util.UUID;
2630

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

3843
public FeedbackRequestExternalRecipientController(FeedbackRequestServices feedbackRequestServices, FeedbackExternalRecipientServices feedbackExternalRecipientServices) {
3944
this.feedbackReqServices = feedbackRequestServices;
@@ -121,4 +126,20 @@ private FeedbackRequestResponseDTO feedbackRequestFromEntity(FeedbackRequest fee
121126
return dto;
122127
}
123128

129+
130+
131+
@Get("/csrf/cookie")
132+
public HttpResponse <?> getCsrfToken() {
133+
LOG.info("CsrfModelProcessor, getCsrfToken");
134+
SecureRandom random = new SecureRandom();
135+
byte[] randomBytes = new byte[24];
136+
random.nextBytes(randomBytes);
137+
String cookieValue = base64Encoder.encodeToString(randomBytes);
138+
139+
return HttpResponse.ok()
140+
// set cookie
141+
.cookie(new NettyCookie("_csrf", cookieValue).path("/").sameSite(SameSite.Strict)).body(cookieValue)
142+
;
143+
}
144+
124145
}

web-ui-external-feedback/src/App.jsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ function App() {
9595
<AppContextProvider>
9696
<ErrorBoundary FallbackComponent={ErrorFallback}>
9797
<div>
98-
<Menu>
99-
<SchemeToggle />
100-
</Menu>
10198
<div className="App">
10299
<Routes />
103100
</div>

web-ui-external-feedback/src/api/api.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { UPDATE_TOAST } from '../context/actions';
22
import qs from 'qs';
33

4-
export const BASE_API_URL = import.meta.env.VITE_APP_API_URL
4+
export const BASE_API_URL = (
5+
import.meta.env.VITE_APP_API_URL
56
? import.meta.env.VITE_APP_API_URL
6-
: 'http://localhost:8080';
7+
: 'http://localhost:8080'
8+
) + '/services/feedback/requests/external/recipients'
9+
;
710

811
export const getAvatarURL = email =>
912
BASE_API_URL +

web-ui-external-feedback/src/api/feedback.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ export const getFeedbackRequestById = async (id, cookie) => {
134134
});
135135
};
136136

137+
export const getFeedbackRequestByIdForExternalRecipient = async (id, cookie) => {
138+
return resolve({
139+
url: `/${id}`,
140+
headers: { 'X-CSRF-Header': cookie, Accept: 'application/json' }
141+
});
142+
};
143+
137144
export const getAnswerByRequestAndQuestionId = async (
138145
requestId,
139146
questionId,

web-ui-external-feedback/src/components/routes/Routes.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import React, { useContext } from 'react';
22
import { Switch, Route } from 'react-router-dom';
33
import { AppContext } from '../../context/AppContext';
4-
import FeedbackSubmitConfirmation from '../feedback_submit_confirmation/FeedbackSubmitConfirmation';
4+
import FeedbackSubmitExternalRecipientPage from "../../pages/FeedbackSubmitExternalRecipientPage.jsx";
55

66

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

1010
return (
1111
<Switch>
12-
<Route exact path="/externalFeedback/">
13-
<FeedbackSubmitConfirmation />
12+
<Route path="/externalFeedback/">
13+
<FeedbackSubmitExternalRecipientPage />
1414
</Route>
1515
</Switch>
1616
);

web-ui-external-feedback/src/context/AppContext.jsx

Lines changed: 1 addition & 247 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,10 @@
11
import React, { useEffect, useReducer, useMemo } from 'react';
22
import { reducer, initialState } from './reducer';
3-
import { getCheckins, getAllCheckinsForAdmin } from './thunks';
43
import {
5-
MY_PROFILE_UPDATE,
64
SET_CSRF,
7-
SET_ROLES,
8-
SET_USER_ROLES,
9-
UPDATE_GUILDS,
10-
UPDATE_MEMBER_SKILLS,
11-
UPDATE_MEMBER_PROFILES,
12-
UPDATE_TERMINATED_MEMBERS,
13-
UPDATE_SKILLS,
14-
UPDATE_CERTIFICATIONS,
15-
UPDATE_TEAMS,
16-
UPDATE_PEOPLE_LOADING,
17-
UPDATE_TEAMS_LOADING
185
} from './actions';
19-
import {
20-
getCurrentUser,
21-
getAllMembers,
22-
getAllTerminatedMembers
23-
} from '../api/member';
24-
import {
25-
selectCanViewCheckinsPermission,
26-
} from './selectors';
27-
import { getAllRoles, getAllUserRoles } from '../api/roles';
28-
import { getMemberSkills } from '../api/memberskill';
296
import { BASE_API_URL } from '../api/api';
30-
import { getAllGuilds } from '../api/guild';
31-
import { getSkills } from '../api/skill';
32-
import { getAllTeams } from '../api/team';
33-
import {getCertifications} from "../api/certification.js";
7+
;
348

359
const AppContext = React.createContext();
3610

@@ -50,26 +24,9 @@ const AppContextProvider = props => {
5024
reducer,
5125
props?.value?.state || initialState
5226
);
53-
const userProfile =
54-
state && state.userProfile ? state.userProfile : undefined;
55-
const memberProfile =
56-
userProfile && userProfile.memberProfile
57-
? userProfile.memberProfile
58-
: undefined;
5927

60-
const id = memberProfile ? memberProfile.id : undefined;
61-
const pdlId = memberProfile ? memberProfile.pdlId : undefined;
6228
const {
6329
csrf,
64-
guilds,
65-
teams,
66-
memberSkills,
67-
memberProfiles,
68-
checkins,
69-
skills,
70-
certifications,
71-
roles,
72-
userRoles
7330
} = state;
7431
const url = `${BASE_API_URL}/csrf/cookie`;
7532
useEffect(() => {
@@ -92,209 +49,6 @@ const AppContextProvider = props => {
9249
getCsrf();
9350
}, [csrf]);
9451

95-
useEffect(() => {
96-
async function getGuilds() {
97-
let res = await getAllGuilds(csrf);
98-
let data =
99-
res.payload &&
100-
res.payload.data &&
101-
res.payload.status === 200 &&
102-
!res.error
103-
? res.payload.data
104-
: null;
105-
if (data) {
106-
dispatch({ type: UPDATE_GUILDS, payload: data });
107-
}
108-
}
109-
if (csrf && !guilds) {
110-
getGuilds();
111-
}
112-
}, [csrf, guilds]);
113-
114-
useEffect(() => {
115-
async function getTeams() {
116-
let res = await getAllTeams(csrf);
117-
let data =
118-
res.payload &&
119-
res.payload.data &&
120-
res.payload.status === 200 &&
121-
!res.error
122-
? res.payload.data
123-
: null;
124-
if (data) {
125-
dispatch({ type: UPDATE_TEAMS, payload: data });
126-
dispatch({ type: UPDATE_TEAMS_LOADING });
127-
}
128-
}
129-
if (csrf && !teams) {
130-
dispatch({ type: UPDATE_TEAMS_LOADING });
131-
getTeams();
132-
}
133-
}, [csrf, teams, dispatch]);
134-
135-
useEffect(() => {
136-
const updateUserProfile = async () => {
137-
let res = await getCurrentUser(csrf);
138-
let profile =
139-
res.payload && res.payload.data && !res.error
140-
? res.payload.data
141-
: undefined;
142-
143-
if (profile) {
144-
dispatch({ type: MY_PROFILE_UPDATE, payload: profile });
145-
}
146-
};
147-
if (csrf && !userProfile) {
148-
updateUserProfile();
149-
}
150-
}, [csrf, userProfile]);
151-
152-
useEffect(() => {
153-
const getAllMemberSkills = async () => {
154-
const res = await getMemberSkills(csrf);
155-
const memberSkills =
156-
res && res.payload && res.payload.data ? res.payload.data : null;
157-
if (memberSkills) {
158-
dispatch({ type: UPDATE_MEMBER_SKILLS, payload: memberSkills });
159-
}
160-
};
161-
if (csrf && !memberSkills) {
162-
getAllMemberSkills();
163-
}
164-
}, [csrf, memberSkills]);
165-
166-
useEffect(() => {
167-
async function getMemberProfiles() {
168-
let res = await getAllMembers(csrf);
169-
let profiles =
170-
res.payload && res.payload.data && !res.error
171-
? res.payload.data
172-
: undefined;
173-
174-
if (profiles) {
175-
dispatch({ type: UPDATE_MEMBER_PROFILES, payload: profiles });
176-
dispatch({ type: UPDATE_PEOPLE_LOADING, payload: false });
177-
}
178-
}
179-
async function getTerminatedMembers() {
180-
let res = await getAllTerminatedMembers(csrf);
181-
let profiles =
182-
res.payload && res.payload.data && !res.error
183-
? res.payload.data
184-
: undefined;
185-
186-
if (profiles) {
187-
dispatch({ type: UPDATE_TERMINATED_MEMBERS, payload: profiles });
188-
}
189-
}
190-
if (csrf && userProfile && !memberProfiles) {
191-
dispatch({ type: UPDATE_PEOPLE_LOADING, payload: true });
192-
getMemberProfiles();
193-
if (userProfile.role?.includes('ADMIN')) {
194-
getTerminatedMembers();
195-
}
196-
}
197-
}, [csrf, userProfile, memberProfiles]);
198-
199-
useEffect(() => {
200-
function getAllTheCheckins() {
201-
if (
202-
userProfile &&
203-
userProfile.permissions?.some(p =>
204-
p?.permission?.includes('CAN_VIEW_CHECKINS_REPORT')
205-
) &&
206-
id &&
207-
csrf
208-
) {
209-
getAllCheckinsForAdmin(dispatch, csrf);
210-
} else if (id && csrf && selectCanViewCheckinsPermission(state)) {
211-
getCheckins(id, pdlId, dispatch, csrf);
212-
}
213-
}
214-
if (csrf && !checkins) {
215-
getAllTheCheckins();
216-
}
217-
}, [csrf, pdlId, id, userProfile, checkins]);
218-
219-
useEffect(() => {
220-
const getAllSkills = async () => {
221-
const res = await getSkills(csrf);
222-
const data =
223-
res &&
224-
res.payload &&
225-
res.payload.data &&
226-
res.payload.status === 200 &&
227-
!res.error
228-
? res.payload.data
229-
: null;
230-
if (data && data.length > 0) {
231-
dispatch({ type: UPDATE_SKILLS, payload: data });
232-
}
233-
};
234-
if (csrf && !skills) {
235-
getAllSkills();
236-
}
237-
}, [csrf, skills]);
238-
239-
useEffect(() => {
240-
const getAllCertifications = async () => {
241-
const res = await getCertifications(csrf);
242-
const data =
243-
res &&
244-
res.payload &&
245-
res.payload.data &&
246-
res.payload.status === 200 &&
247-
!res.error
248-
? res.payload.data
249-
: null;
250-
if (data && data.length > 0) {
251-
dispatch({ type: UPDATE_CERTIFICATIONS, payload: data });
252-
}
253-
};
254-
if (csrf && !certifications) {
255-
getAllCertifications();
256-
}
257-
}, [csrf, certifications]);
258-
259-
useEffect(() => {
260-
const getRoles = async () => {
261-
const res = await getAllRoles(csrf);
262-
const data =
263-
res &&
264-
res.payload &&
265-
res.payload.data &&
266-
res.payload.status === 200 &&
267-
!res.error
268-
? res.payload.data
269-
: null;
270-
if (data && Array.isArray(data) && data.length > 0) {
271-
dispatch({ type: SET_ROLES, payload: data });
272-
}
273-
};
274-
if (csrf && !roles) {
275-
getRoles();
276-
}
277-
}, [csrf, roles]);
278-
279-
useEffect(() => {
280-
const getUserRoles = async () => {
281-
// make call to the API
282-
let res = await getAllUserRoles(csrf);
283-
return res.payload &&
284-
res.payload.data &&
285-
res.payload.status === 200 &&
286-
!res.error
287-
? res.payload.data
288-
: null;
289-
};
290-
291-
if (csrf && !userRoles) {
292-
getUserRoles().then(userRoles => {
293-
dispatch({ type: SET_USER_ROLES, payload: userRoles });
294-
});
295-
}
296-
}, [csrf, userRoles]);
297-
29852
const value = useMemo(() => {
29953
return { state, dispatch };
30054
}, [state]);

0 commit comments

Comments
 (0)