반응형
깃허브 데스크탑으로 프로젝트 관리하기 강의 오픈!! (인프런 바로가기)
참고
- GitHub OAuth Project Settings
- Material UI로 깃허브 로그인 프로필 만들기
- 깃허브 OAuth 콜백 처리하기
- 인증 토큰 획득 서버 구현하기
- 인증 토큰으로 로그인 상태 관리하기
- 로그인 정보를 활용하여 Commit Message 남기기
- 새 창으로 로그인해서 현재 상태 유지하기
이제 인증 정보를 이용하여 README.md를 수정한 유저를 커밋 메시지에 추가해보자.
SimpleToastEditor 수정
SimpleToastEditor에서 GitHub RESTful POST API를 사용하는 fileWrite에 commitMsg 파라미터를 추가한다.
const fileWrite = async (contents, commitMsg) => {
const octokit = new Octokit({
auth: myKey,
});
const currentSHA = await getSHA(octokit);
const result = await octokit.request(
`PUT /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
message: commitMsg,
...
그리고 githublibrary.js에서는 현재 로그인 상태만 알 수 있는 메서드 getLoginStatus를 추가한다.
export const loginCheck = async (setLoginStatus) => {
...
};
export const getLoginStatus = async () => {
let token = localStorage.getItem("GITHUB_TOKEN");
try {
const response = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(response);
return true;
} catch (error) {
console.error("Error fetching user data:", error);
return false;
}
};
이전에 저장 버튼을 누르면 fireWrite가 아래와 같이 호출되었다.
const handleSave = () => {
let markDownContent = editorRef.current.getInstance().getMarkdown();
fileWrite(markDownContent);
};
이제 로그인 된 경우만 write가 가능하도록 아래와 같이 코드를 수정하자.
await을 사용하기 때문에 handleSave도 async가 되어야 한다.
import * as gh from "../githublibrary.js";
...
const handleSave = async () => {
let status = await gh.getLoginStatus();
if(status) {
let loginID = localStorage.getItem("LOGIN_ID");
let markDownContent = editorRef.current.getInstance().getMarkdown();
fileWrite(markDownContent, `submitted by ${loginID}`);
} else {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: '로그인 해주세요!!',
})
}
};
이제 로그인 된 경우만 편집이 가능하고, 누가 편집했는지 알 수 있게 되었다.
전체 코드는 다음과 같다.
githublibrary.js
import axios from "axios";
export const loginCheck = async (setLoginStatus) => {
let token = localStorage.getItem("GITHUB_TOKEN");
try {
const response = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(response);
setLoginStatus(true);
} catch (error) {
console.error("Error fetching user data:", error);
setLoginStatus(false);
}
};
export const getLoginStatus = async () => {
let token = localStorage.getItem("GITHUB_TOKEN");
try {
const response = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(response);
return true;
} catch (error) {
console.error("Error fetching user data:", error);
return false;
}
};
page/SimpleToastEditor.js
import React, { useEffect, useRef, useState } from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import * as gh from "../githublibrary.js";
import Swal from "sweetalert2";
// GitHub RESTful API
import { Octokit } from "@octokit/rest";
// Toast UI Editor
import "@toast-ui/editor/dist/toastui-editor.css";
import "@toast-ui/editor/dist/toastui-editor-viewer.css"; // Viewer css
import { Editor } from "@toast-ui/react-editor";
import Viewer from "@toast-ui/editor/dist/toastui-editor-viewer";
// Dark Theme 적용
// import '@toast-ui/editor/dist/toastui-editor.css';
// import '@toast-ui/editor/dist/theme/toastui-editor-dark.css';
// Color Syntax Plugin
import "tui-color-picker/dist/tui-color-picker.css";
import "@toast-ui/editor-plugin-color-syntax/dist/toastui-editor-plugin-color-syntax.css";
import colorSyntax from "@toast-ui/editor-plugin-color-syntax";
// Table Merged Cell Plugin
import "@toast-ui/editor-plugin-table-merged-cell/dist/toastui-editor-plugin-table-merged-cell.css";
import tableMergedCell from "@toast-ui/editor-plugin-table-merged-cell";
const colorSyntaxOptions = {
preset: [
"#333333", "#666666", "#FFFFFF", "#EE2323", "#F89009", "#009A87", "#006DD7", "#8A3DB6",
"#781B33", "#5733B1", "#953B34", "#FFC1C8", "#FFC9AF", "#9FEEC3", "#99CEFA", "#C1BEF9",
],
};
let myKey = process.env.REACT_APP_MY_TOKEN;
const SimpleToastEditor = () => {
const editorRef = useRef(null);
const [editMode, setEditMode] = useState(false);
const repo = "auto-test";
const path = "README.md";
const getSHA = async (octokit) => {
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
}
);
return result.data.sha;
};
const fileWrite = async (contents, commitMsg) => {
const octokit = new Octokit({
auth: myKey,
});
const currentSHA = await getSHA(octokit);
const result = await octokit.request(
`PUT /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
message: commitMsg,
sha: currentSHA,
committer: {
name: "bloodstrawberry",
email: "bloodstrawberry@github.com",
},
content: `${btoa(unescape(encodeURIComponent(`${contents}`)))}`,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
}
);
console.log(result.status);
};
const fileRead = async () => {
const octokit = new Octokit({
auth: myKey,
});
const result = await octokit.request(
`GET /repos/bloodstrawberry/${repo}/contents/${path}`,
{
owner: "bloodstrawberry",
repo: `${repo}`,
path: `${path}`,
encoding: "utf-8",
decoding: "utf-8",
}
);
return result;
};
const handleSave = async () => {
let status = await gh.getLoginStatus();
if(status) {
let loginID = localStorage.getItem("LOGIN_ID");
let markDownContent = editorRef.current.getInstance().getMarkdown();
fileWrite(markDownContent, `submitted by ${loginID}`);
} else {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: '로그인 해주세요!!',
})
}
};
const initReadMe = async () => {
// let item = localStorage.getItem(CONTENT_KEY);
let result = await fileRead();
let contents = decodeURIComponent(escape(window.atob(result.data.content)));
//console.log(contents);
if (editMode === false) {
const viewer = new Viewer({
el: document.querySelector(".toast-editor-viewer"),
viewer: true,
height: "400px",
usageStatistics: false, // 통계 수집 거부
plugins: [tableMergedCell],
});
viewer.setMarkdown(contents);
}
if (editorRef.current)
editorRef.current.getInstance().setMarkdown(contents);
};
useEffect(() => {
initReadMe();
}, [editMode]);
return (
<div>
<Box sx={{ m: 2 }}>
<h1>Toast UI Editor</h1>
<Button
variant="outlined"
color="secondary"
sx={{ m: 1 }}
onClick={() => setEditMode(!editMode)}
>
{editMode ? "취소하기" : "편집하기"}
</Button>
<Button
variant="outlined"
color="primary"
sx={{ m: 1 }}
onClick={handleSave}
disabled={editMode === false}
>
저장하기
</Button>
{editMode === false && <div className="toast-editor-viewer"></div>}
{editMode === true && (
<Editor
ref={editorRef}
// initialValue={initContents}
height="400px"
placeholder="Please Enter Text."
previewStyle="tab" // or vertical
initialEditType="wysiwyg" // or markdown
// hideModeSwitch={true} // 하단 숨기기
toolbarItems={[
// 툴바 옵션 설정
["heading", "bold", "italic", "strike"],
["hr", "quote"],
["ul", "ol", "task", "indent", "outdent"],
["table", /* "image", */ "link"],
["code", "codeblock"],
]}
//theme="dark"
//useCommandShortcut={false} // 키보드 입력 컨트롤 방지 ex ctrl z 등
usageStatistics={false} // 통계 수집 거부
plugins={[[colorSyntax, colorSyntaxOptions], tableMergedCell]}
/>
)}
</Box>
</div>
);
};
export default SimpleToastEditor;
반응형
'개발 > React' 카테고리의 다른 글
리액트 - 로컬 스토리지 유효기간 설정하기 (Setting Local Storage Expiration Time) (0) | 2023.08.21 |
---|---|
리액트 - 새 창으로 로그인해서 현재 상태 유지하기 (0) | 2023.08.19 |
리액트 - GitHub OAuth 인증 토큰으로 로그인 상태 관리하기 (GitHub OAuth Login Status) (0) | 2023.08.19 |
리액트, Node JS - 인증 토큰 획득 서버 구현하기 (GitHub Access Token Server with Node JS) (0) | 2023.08.19 |
리액트 - 깃허브 OAuth 콜백 처리하기 (GitHub OAuth Callback) (0) | 2023.08.19 |
댓글