Skip to content

Commit

Permalink
Merge pull request #18 from codestates-seb/dev
Browse files Browse the repository at this point in the history
Upstream Pull
  • Loading branch information
KYUNGMINMON authored Jun 26, 2023
2 parents 7296d25 + 7fa62e1 commit 0b9628e
Show file tree
Hide file tree
Showing 24 changed files with 2,046 additions and 164 deletions.
1,822 changes: 1,802 additions & 20 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@uiw/react-md-editor": "^3.23.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.9.0",
Expand All @@ -20,6 +21,7 @@
"react-router-dom": "^6.13.0",
"react-scripts": "5.0.1",
"styled-components": "^5.3.10",
"timeago.js": "^4.0.2",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
25 changes: 12 additions & 13 deletions client/src/components/MarkDownEditor.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { forwardRef } from 'react';
import '@toast-ui/editor/dist/toastui-editor.css'; // Editor 스타일
import { Editor } from '@toast-ui/react-editor';
import styled from 'styled-components';
import MDEditor from '@uiw/react-md-editor';

const EditorWrapper = styled.div`
margin-bottom: 1rem;
`;

const MarkDownEditor = (props, ref) => (
<EditorWrapper>
<Editor
ref={ref}
initialValue={props.content || ' '} // 글 수정 시 사용
/>
</EditorWrapper>
);

export default forwardRef(MarkDownEditor);
export default function MarkDownEditor(props) {
return (
<EditorWrapper data-color-mode={props.theme || 'light'}>
<MDEditor
value={props.value}
onChange={props.onChange}
height={props.height || 200}
/>
</EditorWrapper>
);
}
2 changes: 1 addition & 1 deletion client/src/components/UserCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function UserCard({ type, created, name }) {
return (
<UserInfo>
<UserInfoTop>
{type} <span> {formatAgo(created, 'ko')} </span>
{type} <span> {formatAgo(created)} </span>
</UserInfoTop>
<UserInfoBottom>
<UserAvatar size={32} />
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/common/BlueButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const Button = styled(Link)`
}
`;

export default function BlueButton({ children, onClick }) {
return <Button onClick={onClick}>{children}</Button>;
export default function BlueButton({ children, link, onClick }) {
return (
<Button to={link} onClick={onClick}>
{children}
</Button>
);
}
2 changes: 0 additions & 2 deletions client/src/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ function Home() {
);
const jsonData = await response.json();

console.log(jsonData.data);
setQuestions(jsonData.data);
setIsFetching(false);
};
Expand Down Expand Up @@ -476,7 +475,6 @@ function Home() {
<Questionminilist>
<Questioncontainer>
{/* ⬇모든 Question Items를 포함하는 컴포넌트 최상위 */}
{console.log(questions)}
{Array.isArray(questions) &&
questions?.map((question) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ReactComponent as GoogleLogo } from '../assets/icons/logo_google.svg';
import { ReactComponent as GithubLogo } from '../assets/icons/logo_github.svg';
import { ReactComponent as FacebookLogo } from '../assets/icons/logo_facebook.svg';
import { useNavigate } from 'react-router-dom';
P
import { login } from '../redux/reducers/loginSlice';

const GlobalStyle = createGlobalStyle`
*, *::before, *::after {
Expand Down
35 changes: 19 additions & 16 deletions client/src/pages/QuestionDetail.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import styled from 'styled-components';
import emptyImage from '../assets/imgs/empty.png';
import UserCard from '../components/UserCard';
import BlueButton from '../components/common/BlueButton';

import { useEffect, useState, useRef } from 'react';
import { useEffect, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { ReactComponent as VoteUp } from '../assets/icons/voteup.svg';
import { ReactComponent as VoteDown } from '../assets/icons/votedown.svg';

import MarkDownEditor from '../components/MarkDownEditor';
import UserCard from '../components/UserCard';
import { formatAgo } from '../utils/date';
import BlueButton from '../components/common/BlueButton';
import MarkDownEditor from '../components/MarkDownEditor';

const QuestionDetailWrapper = styled.div`
width: 100%;
Expand Down Expand Up @@ -196,8 +195,7 @@ const AnswerWriteHeader = styled.div`
export default function QuestionDetail() {
const [question, setQuestion] = useState({});
const [isFetching, setIsFetching] = useState(true);
const editorRef = useRef(); // Editor DOM 선택

const [answerValue, setAnswerValue] = useState(`type your answer...`);
const isLogin = true; // 로그인 구현 전 임시변수

const { id } = useParams();
Expand All @@ -215,15 +213,18 @@ export default function QuestionDetail() {
});
}, []);

const onPostEditor = () => {
const content = editorRef.current?.getInstance().getMarkdown();

const onPostEditor = (content) => {
fetch(
`http://ec2-52-78-15-107.ap-northeast-2.compute.amazonaws.com:8080/api/v1/questions/${id}/answers`,
{
method: 'post',
authorization: '',
content: content,
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'qpplication/json',
authorization: '',
},
body: JSON.stringify(content),
},
).then((res) => console.log(res));
};
Expand All @@ -239,11 +240,11 @@ export default function QuestionDetail() {
<QuestionsInfoContainer>
<QuestionsInfoItem>
<span>Asked</span>
<time>{formatAgo(question.createdAt, 'ko')}</time>
<time>{formatAgo(question.createdAt)}</time>
</QuestionsInfoItem>
<QuestionsInfoItem>
<span>Modified</span>
<time>{formatAgo(question.modifiedAt, 'ko')}</time>
<time>{formatAgo(question.modifiedAt)}</time>
</QuestionsInfoItem>
<QuestionsInfoItem>
<span>Viewed</span>
Expand Down Expand Up @@ -351,8 +352,10 @@ export default function QuestionDetail() {
<AnswerWriteHeader>
<AnswerHeaderTitle>Your Answer</AnswerHeaderTitle>
</AnswerWriteHeader>
<MarkDownEditor ref={editorRef} />
<BlueButton onClick={onPostEditor}>Post Your Answer</BlueButton>
<MarkDownEditor value={answerValue} onChange={setAnswerValue} />
<BlueButton onClick={() => onPostEditor(answerValue)}>
Post Your Answer
</BlueButton>
</>
)}
</QuestionDetailWrapper>
Expand Down
14 changes: 2 additions & 12 deletions server/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,11 @@ then
else
echo "> kill -9 $CURRENT_PID" >> /home/ec2-user/log/deploy.log
sudo kill -9 $CURRENT_PID
sleep 5
sleep 10
fi


DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo "> DEPLOY_JAR 배포" >> /home/ec2-user/log/deploy.log
su - ec2-user -c "java -jar $DEPLOY_JAR" >> /home/ec2-user/log/deploy.log 2>/home/ec2-user/log/deploy_err.log &
su - ec2-user -c "java -jar $DEPLOY_JAR --spring.profiles.active=prod" >> /home/ec2-user/log/deploy.log 2>/home/ec2-user/log/deploy_err.log &

sleep 60

if [ -z $CURRENT_PID ]
then
echo "> 현재 구동중인 애플리케이션이 없으므로 다시한번 실행합니다." >> /home/ec2-user/log/deploy.log
echo "> DEPLOY_JAR 배포" >> /home/ec2-user/log/deploy.log
su - ec2-user -c "java -jar $DEPLOY_JAR" >> /home/ec2-user/log/deploy.log 2>/home/ec2-user/log/deploy_err.log &
else
echo "> 실행이 완료됐습니다." >> /home/ec2-user/log/deploy.log
fi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.rainbow.sof.domain.user.auth.jwt.JwtTokenizer;
import com.rainbow.sof.domain.user.dto.singleDto.UserDto;
import com.rainbow.sof.domain.user.entity.User;
import com.rainbow.sof.global.error.BusinessLogicException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
Expand Down Expand Up @@ -37,6 +38,12 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
try {
UserDto.CreationLoginDto creationLoginDto = objectMapper.readValue(request.getInputStream(), UserDto.CreationLoginDto.class);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(creationLoginDto.getUsername(),creationLoginDto.getPassword());
//BadCredentialsException 발생시점 ->
//authenticationProvider 에 올바른 토큰이 오지 않아서 크래댄셜 인증시 db의 내용과
//입력 받은 유저 정보(비밀번호만 다르면)가 다를 때 발생함.
//---> 유저 정보는?
//유저가 없다면 usersDetail 서비스에서 userNotFound 에러를 출력함
//이 외의 에러는 즉, 비밀번호가 일치하지 않을때 BadCredentialsException 발생 !
return authenticationManager.authenticate(authenticationToken);
} catch (IOException e) {
throw new RuntimeException("읽어올 수 없는 사용자 정보 입니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,24 @@ private static void sendErrorResponse(HttpServletResponse response, Gson gson, A
) ? IssueAtAuthenticationProvider :
exception.getMessage();

ErrorResponse errorResponse = getErrorResponse(exceptionMassage);
ErrorResponse errorResponse = getErrorResponse(exceptionMassage,response);

response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());

response.getWriter().write(gson.toJson(errorResponse, ErrorResponse.class));
}

private static ErrorResponse getErrorResponse(String exceptionMassage) {
private static ErrorResponse getErrorResponse(String exceptionMassage,HttpServletResponse response) {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());

if (exceptionMassage == null || exceptionMassage.equals(IssueAtAuthenticationProvider)){

return ErrorResponse.of(HttpStatus.UNAUTHORIZED);
}
else if(exceptionMassage.equals(ExceptionCode.ACCOUNT_RESTRICTED.getMessage())){
response.setStatus(HttpStatus.FORBIDDEN.value());
return ErrorResponse.of(HttpStatus.FORBIDDEN, exceptionMassage);
}
return ErrorResponse.of(HttpStatus.UNAUTHORIZED, exceptionMassage +" : "+HttpStatus.UNAUTHORIZED.getReasonPhrase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import com.rainbow.sof.global.error.BusinessLogicException;
import com.rainbow.sof.global.error.ExceptionCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;

Expand All @@ -27,68 +29,52 @@
@Slf4j
public class OAuth2SuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final DelegateTokenService delegateTokenService;
private final UserService userService;

public OAuth2SuccessHandler(DelegateTokenService delegateTokenService, UserService userService) {
public OAuth2SuccessHandler(DelegateTokenService delegateTokenService) {
this.delegateTokenService = delegateTokenService;
this.userService = userService;
}

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
OAuth2User UserData = (OAuth2User)authentication.getPrincipal();
String email = String.valueOf(UserData.getAttributes().get("email"));
String name = String.valueOf(UserData.getAttributes().get("name"));
User userData = (User) authentication.getPrincipal();
log.info("onAuthenticationSuccess userName: {}", userData.getName());
log.info("onAuthenticationSuccess: userEmail: {}", userData.getEmail());
redirect(request, response,userData);

User createUser = User.builder().email(email)
.name(name)
.password("Q1234123452234522").build();
User oAuth2User= saveUser(createUser);
log.info("onAuthenticationSuccess: {} ", oAuth2User.getName());
log.info("onAuthenticationSuccess: {}" ,oAuth2User.getEmail());
redirect(request, response,oAuth2User);

}

private User saveUser(User oAuth2User) {
try {
return userService.createUser(oAuth2User);
}catch (BusinessLogicException e){

return e.getExceptionCode().equals(ExceptionCode.USER_EXISTS) ?
userService.findByUserFromEmail(oAuth2User.getEmail()) :
null;
}
}

private void redirect(HttpServletRequest request, HttpServletResponse response, User user) throws IOException {
String accessToken = delegateTokenService.delegateAccessToken(user);
String accessToken = "Bearer "+delegateTokenService.delegateAccessToken(user);
String refreshToken = delegateTokenService.delegateRefreshToken(user);


String uri = createURI().toString();
response.setHeader("Authorization", "Bearer " + accessToken);
response.setHeader("Refresh",refreshToken);

getRedirectStrategy().sendRedirect(request, response, "/mypage");
String s = getRedirectStrategy().toString();
String redirectURL = createURI(accessToken,refreshToken).toString();
getRedirectStrategy().sendRedirect(request, response,redirectURL);
}

//TODO: 클라이언트 주소로 변경 필요
private URI createURI() {
private URI createURI(String accessToken,String refreshToken) {
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();// 순서 맞게 보내기위해 LinkedMultiValueMap 사용
queryParams.add("access_token", accessToken);
queryParams.add("refresh_token", refreshToken);
return UriComponentsBuilder
.newInstance()
.scheme("http")
.host("localhost")
// .port(80)
.path("/receive-token.html")
.host("ec2-52-78-15-107.ap-northeast-2.compute.amazonaws.com")
.path("/oAuht")
.queryParams(queryParams)
.build()
.toUri();

// 로컬 클라이언트 테스트 URI
// return UriComponentsBuilder
// .newInstance()
// .scheme("http")
// .host("localhost")
// .port(3000)
// .path("/oAuht")
// .queryParams(queryParams)
// .build()
// .toUri();
}


}
// Map<String, String> oAuth2UserData = new HashMap<>();
// oAuth2UserData.put("email", String.valueOf(oAuth2User.getAttributes().get("email")));
// oAuth2UserData.put("name", String.valueOf(oAuth2User.getAttributes().get("name")));
// User createUser= saveUser(oAuth2UserData);
}
Loading

0 comments on commit 0b9628e

Please sign in to comment.