junggilpark před 1 rokem
rodič
revize
6c6282810c
6 změnil soubory, kde provedl 1295 přidání a 203 odebrání
  1. 730 15
      package-lock.json
  2. 3 1
      package.json
  3. 141 27
      src/app.js
  4. binární
      src/static/images/x-button.png
  5. 96 7
      src/static/styles/custom.css
  6. 325 153
      src/views/hello.html

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 730 - 15
package-lock.json


+ 3 - 1
package.json

@@ -11,6 +11,7 @@
         "@azure/msal-node": "^2.6.6",
         "@microsoft/microsoft-graph-client": "^3.0.7",
         "@microsoft/teams-js": "^2.21.0",
+        "archiver": "^7.0.1",
         "axios": "^1.6.8",
         "cookie-parser": "^1.4.6",
         "cors": "^2.8.5",
@@ -22,7 +23,8 @@
         "fs": "^0.0.1-security",
         "path": "^0.12.7",
         "restify": "^11.1.0",
-        "send": "^0.18.0"
+        "send": "^0.18.0",
+        "unzipper": "^0.11.4"
     },
     "devDependencies": {
         "env-cmd": "^10.1.0",

+ 141 - 27
src/app.js

@@ -11,6 +11,7 @@ const bodyParser = require('body-parser');
 const https = require('https');
 require('dotenv').config({ path: './env/.env.test' });
 const session = require('express-session');
+const messages = require('dote/src/messages');
 
 const serverApp = express();
 
@@ -104,7 +105,7 @@ serverApp.post("/api-get",
 });
 
 serverApp.get("/api-redirect", 
-  //isAuthenticated,
+  isAuthenticated,
   async function (req, res, next) {
       const uri = req.session.apiUri;
       let param = {};
@@ -159,18 +160,44 @@ serverApp.get("/group-redirect",
   async function (req, res, next) {
     // return;
     try {
-        const oneDrive = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/me/drive/root/children", req.session.accessToken);
+        const oneDrive = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/me/drive/root", req.session.accessToken);
+        const sharePointIds = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/me/drive/SharePointIds", req.session.accessToken);
+        // const oneDriveItems = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/me/drive/root/children", req.session.accessToken);
         const graphResponse = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/me/joinedTeams", req.session.accessToken);
         const sites = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/root", req.session.accessToken);
+        const sitesSharePoint = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/root/SharePointIds", req.session.accessToken);
+
         const teams = graphResponse.value;
+        oneDrive.sharePoint = sharePointIds;
+        sites.sharePoint = sitesSharePoint;
         const resultObj = {
-          oneDrive : oneDrive.value,
+          oneDrive : {
+            teams: oneDrive,
+            // items: oneDriveItems.value,
+          },
           joinedTeams : {
             teams : teams,
             items : {},
           },
-          sites : [],
+          sites : {
+            teams : sites,
+            // items : {},
+          },
         }
+        // if (sites) {
+        //   if (Array.isArray(sites)) {
+        //       for(let site of sites) {
+        //         const siteObj = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+site.id+"/drive/items/root/children", req.session.accessToken);
+        //         resultObj.sites.items[site.id] = siteObj.value;
+        //       }
+        //   }
+        //   else if (sites.id) {
+        //     const sitesObj = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+sites.id+"/drive/items/root/children", req.session.accessToken);
+        //     if (sitesObj) {
+        //       resultObj.sites.items[sites.id] = sitesObj.value;
+        //     }
+        //   }
+        // }
         if (teams && teams.length) {
           const options = {
             responseType: 'arraybuffer',
@@ -181,14 +208,12 @@ serverApp.get("/group-redirect",
           };
           for (let team of teams) {
             const item = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/groups/"+team.id+"/drive/items/root/children", req.session.accessToken);
-            let photoRes = await axios.get(process.env.GRAPH_API_ENDPOINT + "v1.0/groups/"+team.id+"/photos/48x48/$value", options);
-            
-            if (photoRes) {
-              photo = Buffer.from(photoRes.data, 'binary').toString('base64');
+            const sharePoint = await fetch(process.env.GRAPH_API_ENDPOINT + "v1.0/groups/"+team.id+"/drive/SharePointIds", req.session.accessToken);
+            if (sharePoint) {
+              team.sharePoint = sharePoint;
             }
             if (item && item.value) {
               resultObj.joinedTeams.items[team.id] = item.value;
-              team.image = photo;
             }
           }
         }
@@ -199,33 +224,122 @@ serverApp.get("/group-redirect",
   }
 )
 
+serverApp.post('/makeFolder', 
+    isAuthenticated,
+    (req, res, next)=>{
+      if (!req.session.accessToken) {
+        return authProvider.acquireToken({
+          scopes: ['.default'],
+          redirectUri: 'https://localhost:53000/redirect',
+          successRedirect: '/makeFolder'
+        })(req, res, next);
+      }
+      next();
+    },
+    async (req, res, next)=>{
+
+      const options = {
+        headers: {
+          Authorization: `Bearer ${req.session.accessToken}`,
+        },
+      };
+      const {siteId, path, param} = req.body;
+      try{
+        const sitesInfo = await axios.get(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+ siteId + path, options);
+        if (sitesInfo.data) {
+          const itemId = sitesInfo.data.id;
+          const result = await axios.post(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+ siteId +"/drive/items/" + itemId +"/children", JSON.parse(param), options);
+          res.json(result.data)
+        }
+      }
+      catch(error) {
+        console.log(error.response.data.error); 
+        
+        // resultObj.success = 'F';
+        // resultObj.message = '선택하신 파일 정보 삭제중 오류가 발생하였습니다.\n' + error.response.data.error.message;
+        // return res.json(resultObj);
+      }
+})
+
+serverApp.post('/uploadItems', 
+  isAuthenticated,
+  (req, res, next)=>{
+    if (!req.session.accessToken) {
+      return authProvider.acquireToken({
+        scopes: ['.default'],
+        redirectUri: 'https://localhost:53000/redirect',
+        successRedirect: '/uploadItems'
+      })(req, res, next);
+    }
+    next();
+  },
+  async (req, res, next)=>{
+    if (req.body) {
+      const {siteId, path, param} = req.body;
+      if (siteId && param) {
+        const options = {
+          headers: {
+            Authorization: `Bearer ${req.session.accessToken}`,
+          },
+        };
+
+        const sitesInfo = await axios.get(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+ siteId + path, options);
+        if (sitesInfo.data) {
+          const itemId = sitesInfo.data.id;
+          const fileInfo = JSON.parse(param);
+          const result = await axios.post(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+ siteId +"/drive/items/"+itemId+':/'+fileInfo.name+':/content', fileInfo, options);
+          res.json(result.data);
+        }
 
-serverApp.post('/getImages/:id', 
+      }
+    }
+})
+
+serverApp.post('/deleteItems', 
   isAuthenticated,
   (req, res, next)=>{
     if (!req.session.accessToken) {
       return authProvider.acquireToken({
         scopes: ['.default'],
         redirectUri: 'https://localhost:53000/redirect',
-        successRedirect: '/getImages/'+req.params.id
+        successRedirect: '/deleteItems'
       })(req, res, next);
     }
     next();
   },
   async (req, res, next)=>{
-    const options = {
-      method: 'GET',
-      url: `https://graph.microsoft.com/v1.0/groups/${req.params.id}/photo/$value`,
-      responseType: 'arraybuffer',
-      headers: {
-        Authorization: `Bearer ${req.session.accessToken}`,
-        ConsistencyLevel: 'eventual',
-      },
-    };
-    await axios.request(options).then((object) => {
-      var photo = Buffer.from(object.data, 'binary').toString('base64');
-      // console.log(object.data);
-      res.json(photo); 
-    });
-
-})
+    if (req.body) {
+      const {siteId, itemIds} = req.body;
+      const resultObj = {success: '', message:''};
+      if (siteId && itemIds) {
+        const itemIdArr = JSON.parse(itemIds);
+        if (itemIdArr.length > 0) {
+          const options = {
+            headers: {
+              Authorization: `Bearer ${req.session.accessToken}`,
+            },
+          };
+          for (let itemId of itemIdArr) {
+            try{
+              await axios.delete(process.env.GRAPH_API_ENDPOINT + "v1.0/sites/"+ siteId + "/drive/items/" + itemId, options);
+            }
+            catch(error) {
+              console.log(error.response.data.error); 
+              
+              resultObj.success = 'F';
+              resultObj.message = '선택하신 파일 정보 삭제중 오류가 발생하였습니다.\n' + error.response.data.error.message;
+              return res.json(resultObj);
+            }
+          }
+          resultObj.success = 'S';
+          resultObj.message = '파일 정보가 삭제되었습니다.';
+          res.json(resultObj);
+        }
+      }
+      else {
+        resultObj.success = 'F';
+        resultObj.message = '파라미터 정보를 확인해주세요.';
+        res.json(resultObj);
+      }
+    }
+  })

binární
src/static/images/x-button.png


+ 96 - 7
src/static/styles/custom.css

@@ -32,7 +32,6 @@ html, body {
   padding: 0 10px;
   box-sizing: border-box;
   background-color: white;
-  border-bottom: 2px solid #9b9898;
   font-weight: bold;
 }
 .content {
@@ -89,9 +88,19 @@ html, body {
 .tree input[type="checkbox"]:checked~ul {
   display: none;
 }
+.tree div {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  margin-bottom: 5px;
+}
 .tree input[type="checkbox"]:checked+label:before{
   content:'▶';
   margin-right: 5px;
+  margin-top: -5px;
+}
+.tree ul li.on {
+  font-weight: bold;
 }
 ul, li {
   user-select: none;
@@ -114,6 +123,7 @@ li {
   cursor: pointer;
   display: flex;
   align-items: center;
+  user-select: none;
 }
 .menu > div:nth-child(2)::before {
   background-image: url('/static/images/plus.png');
@@ -295,29 +305,89 @@ li {
   display: none;
 }
 
-.modal-content {
-  padding: 20px;
+.modal-box {
+  /* padding: 20px; */
   width: 400px;
   height: 225px;
   z-index: 2;
   background-color: white;
   box-shadow: 2px 2px 2px 2px rgb(75, 75, 75);
 }
-.modal .modal-content .title {
+.modal .modal-box .header {
+  position: relative;
+  width: 100%;
+  box-sizing: border-box;
+}
+.modal .modal-box .title {
+  font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
+  -webkit-font-smoothing: antialiased;
+  font-size: 20px;
+  font-weight: 600;
+  color: rgb(97, 97, 97);
+  margin: 0px;
+  min-height: 20px;
+  padding: 16px 46px 20px 24px;
+  line-height: normal;
+}
+.modal .modal-box .modal-content {
+  padding: 0 50px;
+  height: calc(100% - 92px);
+  gap: 10px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.modal .modal-box .modal-content input {
+  width: 100%;
+  height: 30px;
+  padding: 5px;
+
+}
+
+.modal .modal-box .button-box{
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  padding-right: 10px;
+  box-sizing: border-box;
+  gap: 10px;
+  height: 40px;
+}
+.modal .modal-box .button-box > div {
+  padding: 5px 10px;
+  border-radius: 5px;
+  border: 1px solid #b5b0b0;
+  background-color: #b5b0b0;
+  color: white;
   font-weight: bold;
-  font-size: 18px;
-  color: #5f5d5d;
 }
 
+.modal .modal-box .button-box > div:hover{
+  filter: brightness(110%);
+  cursor: pointer;
+}
+
+.modal .modal-box .x-button {
+  display: flex;
+  flex-flow: row;
+  position: absolute;
+  top: 0px;
+  right: 0px;
+  padding: 15px 15px 0px 0px;
+  cursor: pointer;
+}
 .sp-name:hover {
   text-decoration: underline;
 }
 
 .tree li > ul {
   padding: 0px 0px 0px 35px;
-  margin-block-end : 0.5rem;
+  margin-block-end : 0;
   margin-block-start: 0;
 }
+.tree li > ul.group-section {
+  padding: 0px 0px 0px 20px;
+}
 
 .tree label {
   display: flex;
@@ -345,3 +415,22 @@ li {
   cursor: text;
   font-weight: bold;
 }
+
+.click-menu {
+  position: absolute;
+  display: none;
+  background-color: white;
+  top: 40px;
+  box-shadow: 2px 2px 2px 2px #eeeeee;
+}
+
+.click-menu > div {
+  padding: 10px;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+
+.click-menu > div:hover{
+  background-color: #eeeeee;
+}

+ 325 - 153
src/views/hello.html

@@ -35,9 +35,23 @@
                     <div class="sub-menu">
                         <img src="/static/images/menu-icon.png" width="30" height="30" alt="메뉴 아이콘">
                     </div>
-                    <div>새로만들기</div>
-                    <div>업로드</div>
-                    <div>새로고침</div>
+                    <div onclick="menuOpen(event, 'mk-items')">
+                      <div>새로만들기</div>
+                      <div class="mk-items click-menu">
+                        <div onclick="mkdir()"><img src="/static/images/folder.png" width="20" height="20" alt="문서 이미지">&nbsp;폴더</div>
+                        <div><img src="/static/images/docx.svg" width="20" height="20" alt="문서 이미지">&nbsp;Word 문서</div>
+                        <div><img src="/static/images/xlsx.svg" width="20" height="20" alt="문서 이미지">&nbsp;Excel 통합 문서</div>
+                        <div><img src="/static/images/pptx.svg" width="20" height="20" alt="문서 이미지">&nbsp;PowerPoint 프레젠테이션</div>
+                      </div> 
+                    </div>
+                    <div onclick="menuOpen(event, 'upload-items')">
+                      <div>업로드</div>
+                      <div class="upload-items click-menu">
+                        <div style="width: 160px;">폴더</div>
+                        <div style="width: 160px;">파일</div>
+                      </div> 
+                    </div>
+                    <div onclick="refreshDrive()">새로고침</div>
                     <div class="one-drive-button">OneDrive에서 열기</div>
                 </div>
                 <div class="panel"></div>
@@ -53,22 +67,13 @@
             </section>
         </div>
     </div>
-    <div class="modal">
-        <div class="modal-content">
-            <div class="title">이름 바꾸기</div>
-            <input type="text" name="file_name" id="" value="">.pdf
-            <div>
-                <div class="name-btn">이름 바꾸기</div>
-                <div class="name-btn">취소</div>
-            </div>
-        </div>
-    </div>
   </body>
 </html>
 <script>
   const groupId = '3df73dac-a8bc-4dd0-9159-fdb2c696c067';
   const groupMap = new Map();
   let _selectedData = [];
+  let _listData = [];
   $(()=>{
     microsoftTeams.appInitialization.notifySuccess();
     getGroupList();
@@ -76,9 +81,18 @@
     window.oncontextmenu = function () {
         return false;
     };
+    window.addEventListener('click', function() {
+      $('.click-menu').css('display', 'none');
+    })
 
   });
 
+  function menuOpen(event, className) {
+    event.preventDefault();
+    event.stopPropagation();
+    $('.click-menu:not(.'+className+')').css('display', 'none');
+    $('.' + className).toggle();
+  }
 
   function drawDriveFiles(jsonData, parentData, name) {
       _selectedData = [];
@@ -96,7 +110,7 @@
       if (jsonData && jsonData.value && jsonData.value.length > 0) {
         if (jsonData.value[0].webUrl) {
           $oneDriveBtn.on('click', ()=>{
-            window.open(obj.webUrl);
+            window.open(jsonData.value[0].webUrl);
           });
         };
         _selectedData = jsonData;
@@ -124,6 +138,9 @@
               if (obj.file.mimeType && obj.file.mimeType.includes('image')){
                 ext = 'photo';
               }
+              else if (['txt'].includes(ext)) {
+                ext = 'txt';
+              }
               else if (['pptx', 'ppt', 'pptm'].includes(ext)) {
                 ext = 'pptx';
               }
@@ -169,7 +186,7 @@
             }
 
             // let method = `findOneDriveChildrenItems('${obj.id}')`;(siteId, path, name, value)
-            let method = `siteDriveChildrenItems('${obj.parentReference.siteId}','${obj.parentReference.path + '/' + obj.name}','${name}')`;
+            let method = `siteDriveChildrenItems('${obj.parentReference.siteId}','${obj.parentReference.path + '/' + obj.name}','${name}', null, event)`;
             if (obj.file) {
               method = `downloadItems('${obj['@microsoft.graph.downloadUrl']}', '${obj.name}', event)`;
             }
@@ -215,12 +232,13 @@
               if ($('.toggle-box')[0]) {
                 $('.toggle-box').remove();
               }
+
               const {clientX, clientY} = e;
                 const toggleBox = $(`<div class="toggle-box" style="position:absolute; top:${clientY}; left: ${clientX}">
                     <div>편집</div>
                     <div>탭으로 설정</div>
                     <div>다운로드</div>
-                    <div>삭제</div>
+                    <div onclick="deleteItem()">삭제</div>
                     <div>이동</div>
                     <div>복사</div>
                     <div onclick="nameChange()">이름 바꾸기</div>
@@ -232,7 +250,11 @@
         else {
             if (parentData && parentData.folder && parentData.folder.childCount === 0) {
                 const refData = parentData.parentReference;
-                panelStr = drawPath(refData.path +'/' + parentData.name, refData.siteId ,name);
+                let path = '';
+                if (refData.path) {
+                  path = refData.path +'/' + parentData.name;
+                }
+                panelStr = drawPath(path, refData.siteId, name);
                 $oneDriveBtn.off('click');
                 
                 if (parentData.webUrl){
@@ -251,51 +273,85 @@
         panel.html(panelStr);
     }
 
-    // callApi('get','/deviceManagement', (jsonData)=>{
-    //     console.log(jsonData);
-    // })
-    function drawDrivePath(path, name, siteId) {
-      if (path) {
-        let formatPath = path.substring(path.lastIndexOf('root:') + 5);
-        
-        if (formatPath) {
-          formatPath = formatPath.substring(1);
-          formatPath = formatPath.split('/');
-          panelStr = `<span class="panel-item" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${name}', '${siteId}')">${name}</span>`;
-          let itemPath = "/drive/root:";
-          if (Array.isArray(formatPath)) {
-            for(let ii = 0; ii < formatPath.length; ii++) {
-              let pathName = formatPath[ii];
-              let className = 'panel-item';
-              itemPath += "/" + pathName;
-              let method = `drawDriveFiles('${itemPath}', event)`;
-              if (formatPath.length - 1 === ii) {
-                className += ' on';
-                method = '';
-              }
-              
-              panelStr += `<span> > </span><span class="${className}" onclick="${method}">${pathName}</span>`;
+    //새로고침 이벤트
+    function refreshDrive() {
+        const selectedDrive = $('.panel-item.on');
+        if (selectedDrive[0]) {
+          selectedDrive.removeClass('on');
+          selectedDrive.click();
+        }
+    }
+
+    //삭제 이벤트
+    function deleteItem() {
+      const checkArr = $('.file-content input[type="checkbox"]');
+      const checkedArr = [];
+      let siteId = getSitesId();
+
+      if (!siteId) return alert('그룹 정보를 확인 할 수 없습니다.');
+      
+      if (checkArr.length > 0) {
+        for (let ii = 0; ii < checkArr.length; ii++) {
+          if (checkArr.eq(ii).is(':checked')) {
+            const title = checkArr.eq(ii).parent().next().text();
+            const team = _listData.joinedTeams;
+            const idx = team.teams.findIndex(obj => obj.sharePoint.siteId === siteId);
+            if (idx >= 0) {
+              const sameIndex = team.items[team.teams[idx].id].findIndex(obj => obj.id === checkArr.eq(ii).val());
+              if (sameIndex >= 0) {
+                return alert('채널 정보는 삭제하실수 없습니다.');
+              };
             }
+
+            checkedArr.push(checkArr.eq(ii).val());
           }
-          return panelStr;
+        }
+        if (checkedArr.length === 0) {
+          alert('선택된 정보가 없습니다. 삭제하실 파일을 먼저 선택해주세요.');
+        }
+        else {
+          if (confirm('선택된 파일을 삭제하시겠습니까?')) {
+              $.ajax({
+                method:'post',
+                url : "/deleteItems",
+                data: {
+                  siteId: siteId,
+                  itemIds : JSON.stringify(checkedArr),
+                },
+                success: (res)=> {
+                  if (res.success === 'S') {
+                      const selectedDrive = $('.panel-item.on');
+                      selectedDrive.removeClass('on');
+                      selectedDrive.click();
+                  }
+                  alert(res.message);
+                },
+                error: (error)=> {
+                  console.log(error);
+                }
+              })
+            }
+            else {
+              alert('선택된 그룹 정보가 없습니다. 선택 그룹을 확인해 주세요.');
+            }
         }
       }
-      return `<span class="panel-item on">${name}</span>`;
     }
 
     function drawPath(path, siteId, name) {
       let imgSrc = '';
       let panelStr = '';
-      if ($('#'+siteId).next().find('img')[0]) {
-        imgSrc = $('#'+siteId).next().find('img').attr('src');
+      if ($('#'+siteId + '_li').find('img')[0]) {
+        imgSrc = $('#'+siteId + '_li').find('img').attr('src');
       }
+
       if (path) {
         let formatPath = path.substring(path.lastIndexOf('root:') + 5);
         
         if (formatPath) {
           formatPath = formatPath.substring(1);
           formatPath = formatPath.split('/');
-          panelStr = `<span class="panel-item" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${name}', '${siteId}')">`;
+          panelStr = `<span class="panel-item" id="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${name}', '${siteId}', event)">`;
           if (imgSrc) {
             panelStr += `<img style="margin-right:5px;" width="24" height="24" src="${imgSrc}" alt="이미지">`
           }
@@ -306,10 +362,10 @@
               let pathName = formatPath[ii];
               let className = 'panel-item';
               itemPath += "/" + pathName;
-              let method = `siteDriveChildrenItems('${siteId}','${itemPath}', '${name}')`;
+              let method = `siteDriveChildrenItems('${siteId}','${itemPath}', '${name}', null, event)`;
               if (formatPath.length - 1 === ii) {
                 className += ' on';
-                method = '';
+                // method = '';
               }
               
               panelStr += `<span> > </span><span class="${className}" onclick="${method}">${pathName}</span>`;
@@ -319,7 +375,7 @@
         }
       }
       
-      panelStr = `<span class="panel-item on">`;
+      panelStr = `<span class="panel-item on" id="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${name}', '${siteId}', event)">`;
       if (imgSrc) {
         panelStr += `<img style="margin-right:5px;" width="24" height="24" src="${imgSrc}" alt="이미지">`
       }
@@ -328,6 +384,7 @@
 
       return panelStr;
     }
+
     function nameChange() {
         if ($('.file-content > .on .file_name')[0]) {
         }
@@ -352,14 +409,6 @@
             e.preventDefault();
             $(this).css('background-color', '#f5f5f5');
             const transfer = e.originalEvent.dataTransfer;
-            console.log(e.dataTransfer);
-            console.log(transfer.items);
-            if (transfer.items.length > 0) {
-              for (let ii=0; ii < transfer.items.length; ii++) {
-                entries[0] = e.dataTransfer.items[ii].webkitGetAsEntry();
-                console.log(entries[0]);
-              }
-            }
             if (transfer && transfer.files && transfer.files.length > 0) {
                 for (let ii = 0; ii < transfer.files.length; ii++) {
                   console.log(transfer.files[ii]);
@@ -426,36 +475,45 @@
         });
     }
 
-    function makeFolder(type, uri, scopes, callBackMethod, args, params) {
-      $.ajax({
-            method: 'post',
-            url : "/api-"+type,
-            data: {
-              api_uri: uri,
-              scopes : scopes,
-              param : params,
-            },
-            success: (res)=> {
-              callBackMethod(res, args);
-            },
-            error: (error)=> {
-              console.log(error);
-            }
-      });
-    }
-
-    function siteDriveChildrenItems(siteId, path, name, value) {
+    function siteDriveChildrenItems(siteId, path, name, value, event) {
+      event.preventDefault();
+      event.stopPropagation();
+      if ($(event.target).hasClass('on')) {
+        return;
+      }
       if (value) {
-        $('.tree.group input').prop('checked', true);
+        // $('.tree.group input').prop('checked', true);
         $('input[value="'+value+'"]').prop('checked', false);
         if ($('.panel').children().text() === name) {
           return;
         }
       }
-      callApi('get', '/sites/' +siteId +'/'+ path, (jsonData)=>{
+      console.log('/sites/' +siteId + path);
+      callApi('get', '/sites/' +siteId + path, (jsonData)=>{
         if (jsonData && jsonData.id) {
+          if (jsonData.folder && jsonData.folder.childCount === 0) {
+              if (path.indexOf('root:') < 0) {
+                path = '';
+              }
+              const panelStr = drawPath(path, siteId, name);
+              const $oneDriveBtn = $('.one-drive-button');
+              const $fileContent = $('.file-content');
+              const $panel = $('.panel');
+              $oneDriveBtn.off('click');
+              if (jsonData.webUrl){
+                $oneDriveBtn.on('click', ()=>{
+                  window.open(jsonData.webUrl);
+                });
+              }
+
+              $fileContent.html(`<div class="empty-box">
+                                  <img src="/static/images/empty_folder_v2.svg" alt="이미지">
+                                  <div>이 폴더는 비어 있습니다.</div>
+                                </div>`);
+              $panel.html(panelStr);
+              return;
+          }
           callApi('get', '/sites/' +siteId +'/drive/items/'+jsonData.id+'/children', (childrenData)=>{
-            // drawOneDrive(childrenData, jsonData, name);
             drawDriveFiles(childrenData, jsonData, name);
           },null); 
         }
@@ -520,93 +578,87 @@
           }
       })
     }
-//sites/2ec19976-da37-4d7e-993a-fe82cf97a586/drive/items/01ILDTREXEZN5EXKD5YJHLNYXU6HTAX5VS/children
-//oneDrive => /me/drive/items/${item.id}/children
+
     function drawList(jsonData) {
       const group = $('.group');
       group.empty();
       if (jsonData) {
+          _listData = jsonData;
+          const groupImageUrl = '/_api/siteiconmanager/getsitelogo?type=1';
           const {oneDrive, joinedTeams, sites} = jsonData;
           let parentId = '';
           let siteId = '';
-          if (oneDrive && oneDrive.length > 0) {
-            if (oneDrive[0].parentReference) {
-              siteId = oneDrive[0].parentReference.siteId;
-            }
+          let str = "";
+        
+          
+          if (joinedTeams && joinedTeams.teams.length > 0) {
+            str += `<li>
+                      <input id="my-team" type="checkbox">
+                      <label for="my-team">내 Teams 그룹</label>
+                      <ul class="group-section">
+                    `
+            joinedTeams.teams.forEach((team)=>{
+              const items = joinedTeams.items[team.id];
+              let siteId = team.sharePoint.siteId;
+              // onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${team.displayName}', '${siteId}', event)"
+              str += `<li id="${siteId}_li">
+                        <input type="checkbox" checked="false" id="${siteId}_check" value="${siteId}">
+                        <label for="${siteId}_check"><img width="24" height="24" src="${team.sharePoint.siteUrl}${groupImageUrl}" alt="이미지">&nbsp;${team.displayName}</label>
+                        <ul>`;
+                        
+                        if (items && items.length > 0) {
+                          items.forEach((item)=>{
+                            str +=`<li id="${item.id}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root:/${item.name}', '${team.displayName}', null, event)">${item.name}</li>`
+                          })
+                        }
+              str +=`</ul></li>`;
+            })
+            str += '</ul></li>';
           }
-          // <input type="checkbox" checked="false" id="my-one-drive" value="${parentId}" onclick="showOneDrive(event)">
-          //siteDriveChildrenItems(siteId, path, name) 
-          let str = `<li>
-                      <input type="checkbox" checked="false" id="${siteId}" value="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', 'One Drive', '${siteId}')">
-                      <label for="${siteId}">One Drive</label>
-                      <ul>`;
-                      if (oneDrive && oneDrive.length > 0) {
-                        oneDrive.forEach((drive)=>{
-                          str +=`<li id="${drive.id}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root:/${drive.name}', 'One Drive')">${drive.name}</li>`
-                        })
-                      }
-              str += `</ul>
-                    </li>`;
-              if (joinedTeams && joinedTeams.teams.length > 0) {
-                joinedTeams.teams.forEach((team)=>{
-                  const items = joinedTeams.items[team.id];
-                  let siteId;
-                  let path;
-                  if (items[0]) {
-                    let joinedRef = items[0].parentReference;
-                    siteId = joinedRef.siteId;
-                    path = joinedRef.path;
-                  }
-                  str += `<li>
-                            <input type="checkbox" checked="false" id="${siteId}" value="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${team.displayName}', '${siteId}')">
-                            <label for="${siteId}"><img width="24" height="24" src="data:image/jpeg;base64, ${team.image}" alt="이미지">&nbsp;${team.displayName}</label>
-                            <ul>`;
-                            
-                            if (items && items.length > 0) {
-                              items.forEach((item)=>{
-                                str +=`<li id="${item.id}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root:/${item.name}', '${team.displayName}')">${item.name}</li>`
-                              })
-                            }
-                  str +=`</ul></li>`;
-                })
+          if (oneDrive) {
+            const {teams, items} = oneDrive;
+            const sharePoint = teams.sharePoint;
+            siteId = sharePoint.siteId;
+              // str += `<div>
+              //           <input type="checkbox" checked="false" id="${siteId}" value="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', 'One Drive', '${siteId}', event)">
+              //           <label for="${siteId}"><img width="24" height="24" src="${sharePoint.siteUrl}${groupImageUrl}" alt="그룹 이미지">&nbsp;One Drive</label>
+              //         </div>`;
+              str += `<div id="${siteId}_li" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', 'One Drive', '${siteId}', event)">
+                        <img width="24" height="24" src="${sharePoint.siteUrl}${groupImageUrl}" alt="그룹 이미지">&nbsp;One Drive
+                      </div>`;
+          }
+
+          if (sites) {
+              let {teams, items} = sites;
+              if (!Array.isArray(teams)) {
+                teams = [teams];
+              }
+              for (let team of teams) {
+                // const items = sites.items[team.id];
+                let siteId = team.sharePoint.siteId;
+                let path;
+                let imageUrl;
+                  // str += `<li>
+                  //         <input type="checkbox" checked="false" id="${siteId}" value="${siteId}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${team.displayName}', '${siteId}', event)">
+                  //         <label for="${siteId}"><img width="24" height="24" src="${team.sharePoint.siteUrl}${groupImageUrl}" alt="이미지">&nbsp;${team.displayName}</label>
+                  //         <ul>`;
+                  //         if (items && items.length > 0) {
+                  //           items.forEach((item)=>{
+                  //             str +=`<li id="${item.id}" onclick="siteDriveChildrenItems('${siteId}', '/drive/root:/${item.name}', '${team.displayName}', null, event)">${item.name}</li>`
+                  //           })
+                  //         }
+                  // str +=`</ul></li>`;
+                  str += `
+                        <div id="${siteId}_li" onclick="siteDriveChildrenItems('${siteId}', '/drive/root', '${team.displayName}', '${siteId}', event)">
+                          <img width="24" height="24" src="${team.sharePoint.siteUrl}${groupImageUrl}" alt="그룹 이미지">&nbsp;${team.displayName}
+                        </div>`;
               }
-              group.append($(str));
-      }
-    }
 
-    function showOneDrive(event) {
-      $('.tree.group input[type="checkbox"]').prop('checked', true);
-      event.target.checked = false;
-      if ($(event.target).next().text() === $('.panel').children().first().text()) {
-        return;
+          }
+          group.append($(str));
       }
-      callApi('get', '/me/drive/root/children', (jsonData)=>{
-        drawOneDrive(jsonData, '', $(event.target).next().text());
-      })
     }
 
-    function DrawOneDriveFile(id, name) {
-      callApi('get', '/me/drive/items/' + id + '/children', (jsonData)=>{
-        drawOneDrive(jsonData, name, id);
-      })
-    }
-
-    function showJoinedTeam(id, name, event) {
-      // const $target = $(event.target);
-      // const isChecked = $target.is(':checked');
-      // if (isChecked) {
-      //   $target.prop('checked', 'checked');
-      //   return;
-      // }
-      $('.tree.group input[type="checkbox"]').prop('checked', true);
-      event.target.checked = false;
-      if ($(event.target).next().text() === $('.panel').children().first().text()) {
-        return;
-      }
-      callApi('get', '/groups/'+id+'/drive/items/root/children', (jsonData)=>{
-        drawFileList(jsonData, name, id, $(event.target));
-      })
-    }
 
     function sorting(type) {
       const $sortingColumn = $('.head-'+type);
@@ -655,4 +707,124 @@
     window.URL.revokeObjectURL(downloadUrl);
   }
 
+  function makeFolder() {
+    const $folderName = $('#folder_name');
+    const name = $folderName.val();
+    if (!name || !name.trim()) {
+      $folderName.focus();
+      return alert("폴더명을 입력해주세요.");
+    }
+    let siteId = getSitesId();
+    if (siteId === null) {
+      return alert('선택된 그룹 정보를 찾을 수 없습니다. 생성할 그룹을 선택해주세요.');
+    }
+    
+    const groupIndex = _listData.joinedTeams.teams.findIndex(obj => obj.sharePoint.siteId === siteId);
+    const pathArr = $('.panel').children();
+
+    if (groupIndex >= 0 && $('.panel').children().length === 1) {
+        return alert('채널 리스트를 먼저 선택해 주세요.');
+    }
+    let sitePath = '/drive/root'
+    if (pathArr.length > 1) {
+      sitePath += ':';
+      for (let ii = 0; ii < pathArr.length; ii++) {
+        const path = pathArr.eq(ii).text();
+        if (ii !== 0 && path !== " > ") {
+          sitePath += "/" + path; 
+        }
+      }
+    }
+
+    $.ajax({
+      method: 'post',
+      data : {
+        siteId : siteId,
+        path : sitePath,
+        param : JSON.stringify({
+          name: name,
+          folder: { },
+          '@microsoft.graph.conflictBehavior': 'rename'
+        })
+      },
+      url : '/makeFolder',
+      success: (res) => {
+        alert('폴더가 생성되었습니다.\n폴더명 : '+ res.name);
+        $('.modal').remove();
+        const selectDrive = $('.panel-item.on');
+        selectDrive.removeClass('on');
+        selectDrive.click();
+        
+      },
+      error: (error) => {
+        console.log('==============error=============\n');
+        console.log(error);
+      }
+      
+    })
+  }
+
+  function mkdir() {
+    const modalContainer = $(
+      `<div class="modal" style="display: flex;">
+          <div class="modal-box">
+              <div class="header">
+                <div class="title">폴더 생성</div>
+                <div class="x-button">
+                  <span><img src="/static/images/x-button.png" width="15" height="15" alt="닫기 버튼" onclick="modalClose()"></span>
+                </div>
+              </div>
+              <div class="modal-content">
+                <div>폴더명</div>
+                <input type="text" name="file_name" id="folder_name" value="">
+              </div>
+              <div class="button-box">
+                  <div class="name-btn" onclick="makeFolder()">만들기</div>
+                  <div class="name-btn" onclick="modalClose()">취소</div>
+              </div>
+          </div>
+      </div>`);
+      $('body').append(modalContainer);
+    
+    // callApi('post', '/sites/' +siteId +'/drive/items/'++'/children', (jsonData)=>{
+    //   console.log(jsonData);
+    //   callApi('post', '')
+    // })
+    
+  }
+
+  function modalClose(){
+      $('.modal').remove();
+  }
+
+  function getSitesId() {
+    let siteId = null;
+    if ($('.panel').children().first()[0]) {
+        siteId = $('.panel').children().first().attr('id');
+    }
+    return siteId;
+  }
+
+  function changeNames() {
+    const modalContainer = $(
+      `<div class="modal" style="display: flex;">
+          <div class="modal-box">
+              <div class="header">
+                <div class="title">이름 바꾸기</div>
+                <div class="x-button">
+                  <span><img src="/static/images/x-button.png" width="15" height="15" alt="닫기 버튼"></span>
+                </div>
+              </div>
+              <div class="modal-content">
+                <div>이름</div>
+                <input type="text" name="file_name" id="" value="">
+              </div>
+              <div class="button-box">
+                  <div class="name-btn">이름 바꾸기</div>
+                  <div class="name-btn">취소</div>
+              </div>
+          </div>
+      </div>`);
+  }
+
 </script>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů