junggilpark před 1 rokem
rodič
revize
81f3fa0023
3 změnil soubory, kde provedl 327 přidání a 116 odebrání
  1. 102 58
      src/app.js
  2. 73 0
      src/static/styles/custom.css
  3. 152 58
      src/views/hello.html

+ 102 - 58
src/app.js

@@ -13,8 +13,24 @@ const JSZIP = require('jszip');
 require('dotenv').config({ path: './env/.env.test' });
 const session = require('express-session');
 const multer  = require('multer');
-const { throws } = require('assert');
-let _ZIP;
+const {DeviceCodeCredential} = require('@azure/identity');
+const {TokenCredentialAuthenticationProvider} = require('@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials')
+const {Client} = require('@microsoft/microsoft-graph-client')
+
+const credential = new DeviceCodeCredential({
+  tenantId : process.env.TENANT_ID,
+  clientId : process.env.CLIENT_ID,
+  userPromptCallback: (info) => {
+    console.log(info.message);
+  },
+});
+
+const authPr = new TokenCredentialAuthenticationProvider(credential, {
+  scopes: ['.default'],
+});
+
+const graphClient = Client.initWithMiddleware({ authProvider: authPr });
+
 const storage =  multer.diskStorage({
   destination: function (req, file, cb) { 
     cb(null, 'uploads/')  
@@ -76,6 +92,9 @@ server.listen(SERVER_PORT, function () {
 serverApp.get("/tab", 
   isAuthenticated, 
   async function (req, res, next) {
+
+    // const result = await graphClient.api('/me').get();
+    // console.log(result);
     res.sendFile(path.join(__dirname, "/views/hello.html"), 
       { idTokenClaims: req.session.account.idTokenClaims }
     );
@@ -602,10 +621,13 @@ serverApp.post('/api/delete',
               await axios.delete(endPoint + "/sites/"+ siteId + "/drive/items/" + itemId, options);
             }
             catch(error) {
-              console.log(error.response.data.error); 
-              
               resultObj.success = 'F';
-              resultObj.message = '선택하신 파일 정보 삭제중 오류가 발생하였습니다.<br>' + error.response.data.error.message;
+              let message = '선택하신 파일 정보 삭제중 오류가 발생하였습니다.';
+              if (error && error.response && error.response.data && error.response.data.error && error.response.data.error.message) {
+                console.log(error.response.data.error.message);
+                message += '<br>' + error.response.data.error.message;
+              }
+              resultObj.message = message;
               return res.json(resultObj);
             }
           }
@@ -664,64 +686,86 @@ serverApp.post('/api/update-name',
         resultObj.message = '파라미터 정보를 확인해주세요.';
         return res.json(resultObj);
       }
-  })
-
-
+  });
   
-serverApp.post('/api/move-item', 
-  isAuthenticated,
-  (req, res, next)=>{
-    if (!req.session.accessToken) {
-      return authProvider.acquireToken({
-        scopes: ['.default'],
-        redirectUri: 'https://localhost:53000/redirect',
-        successRedirect: '/api/move-item'
-      })(req, res, next);
-    }
-    next();
-  },
-  async (req, res, next)=>{
-    if (req.body) {
-      const {id, name, itemId, siteId} = req.body;
-      const resultObj = {message:'', successItems : [], failItems : []};
-      if (name && isNaN(name)) {
-        const nameArray = JSON.parse(name);
-        const options = {
-          headers: {
-            Authorization: `Bearer ${req.session.accessToken}`,
-            ContentType: "application/json",
-          },
-        };
+serverApp.post('/api/copy-item', 
+isAuthenticated,
+(req, res, next)=>{
+  if (!req.session.accessToken) {
+    return authProvider.acquireToken({
+      scopes: ['.default'],
+      redirectUri: 'https://localhost:53000/redirect',
+      successRedirect: '/api/copy-item'
+    })(req, res, next);
+  }
+  next();
+},
+async (req, res, next)=>{
+  if (req.body) {
+    const {id, name, siteId, driveId, text} = req.body;
+    const resultObj = {message:'', successItems : [], failItems : [], locations: []};
+    if (name && isNaN(name)) {
+      const nameArray = JSON.parse(name);
+      const options = {
+        headers: {
+          Authorization: `Bearer ${req.session.accessToken}`,
+          ContentType: "application/json",
+        },
+      };
 
-        if (nameArray && nameArray.length > 0) {
-          for (let moveItem of nameArray) {
-            if (moveItem) {
-              const param = {
-                parentReference: {
-                  id: id
-                },
-                name: moveItem.name
-              };
-              try {
-                const result = await axios.patch(`${endPoint}/sites/${siteId}/drive/items/${moveItem.id}`, param, options);
-                // const remove = await axios.delete(`${endPoint}/sites/${siteId}/drive/items/${moveItem.id}`, options);
-                console.log(result.data);
-                if (result.data) {
-                  resultObj.successItems.push(moveItem.name);
-                }
-              }
-              catch (error) {
-                // console.log(error);
-                console.log(error.message);
-                console.log(error.name);
-                console.log(error.errors);
-                resultObj.failItems.push(moveName.name);
+      if (nameArray && nameArray.length > 0) {
+        for (let moveItem of nameArray) {
+          if (moveItem) {
+            const param = {
+              parentReference: {
+                id: id,
+                driveId : driveId,
+              },
+              name: moveItem.name
+            };
+            try {
+              const result = await axios.post(`${endPoint}/sites/${siteId}/drive/items/${moveItem.id}/copy`, param, options);
+              if (result) {
+                console.log(result);
+                resultObj.successItems.push(moveItem.name);
+                resultObj.locations.push(result.headers.location);
               }
             }
+            catch (error) {
+              // console.log(error);
+              console.log(error.message);
+              console.log(error.name);
+              console.log(error.errors);
+              resultObj.failItems.push(moveItem.name);
+            }
           }
-          resultObj.message = `요청 하신 ${nameArray.length} 개 파일 중 ${ resultObj.successItems.length} 개 파일이 이동 되었습니다.`;
         }
+        resultObj.message = `요청 하신 ${nameArray.length} 개 파일 중 ${ resultObj.successItems.length} 개 파일이 ${text} 되었습니다.`;
       }
-      return res.json(resultObj);
     }
-  });
+    return res.json(resultObj);
+  }
+});
+  
+serverApp.post('/api/loading', 
+  async (req, res, next)=>{
+    if (req.body) {
+      const {url} = req.body;
+      if (url) {
+        try {
+          const result = await axios.get(`${url}`);
+          if (result && result.data) {
+            console.log(result.data);
+            return res.json(result.data);
+          }
+        }
+        catch (error) {
+          // console.log(error);
+          console.log(error.message);
+          console.log(error.name);
+          console.log(error.errors);
+          return res.json(error);
+        }
+      }
+  }
+});

+ 73 - 0
src/static/styles/custom.css

@@ -713,7 +713,80 @@ html, body {
   box-sizing: border-box;
   overflow: auto;
   flex-direction: column;
+  position: relative;
+}
+
+.modal .modal-move-box .right-box .content .loading-box {
+  position: absolute;
+  right: 0;
+  top: 0;
+  width: 245px;
+  height: auto;
+  background-color: white;
+  border: 1px solid #eeeeee;
+}
+@keyframes spinCircle {
+  from {
+    transform: rotate(0);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+.modal .modal-move-box .right-box .content .loading-box > div > div img {
+  animation-name: spinCircle; 
+  animation-duration: .8s; 
+  animation-iteration-count: infinite;
+}
+.modal .modal-move-box .right-box .content .loading-box > div > div:nth-child(1) > div:nth-child(1) {
+  width: calc(100% - 50px);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.modal .modal-move-box .right-box .content .loading-box > div > div:nth-child(1) {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.modal .modal-move-box .right-box .content .loading-box .loading-gauge-box{
+  display: flex;
+  align-items: center;
+  height: 30px;
+  width: 100%;
 }
+.modal .modal-move-box .right-box .content .loading-box .loading-gauge-box > div:nth-child(2) {
+  width: 60px;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+}
+.modal .modal-move-box .right-box .content .loading-box .loading-gauge-box > div:nth-child(1) {
+  width: calc(100% - 60px);
+  height: 10px;
+  position: relative;
+}
+.modal .modal-move-box .right-box .content .loading-box .loading-gauge-box .loading-background {
+  width: 100%;
+  height: 10px;
+  position: absolute;
+  background-color: #eeeeee;
+  border: 1px solid #eeeeee;
+  border-radius: 5px;
+}
+.modal .modal-move-box .right-box .content .loading-box .loading-gauge-box .loading-gauge {
+  width: 0;
+  height: 10px;
+  position: absolute;
+  background-color: rgb(17, 212, 99);
+  border: 1px solid rgb(17, 212, 99);
+  border-radius: 5px;
+}
+
+.modal .modal-move-box .right-box .content .loading-box > div{
+  padding: 10px;
+}
+
 .modal .modal-move-box .right-box .panel{
   width: 100%;
   height: 59px;

+ 152 - 58
src/views/hello.html

@@ -178,13 +178,17 @@
   function menuOpen(event, className) {
     event.preventDefault();
     event.stopPropagation();
+    const toggleBox = document.getElementsByClassName('toggle-box');
+    if (document.getElementsByClassName('toggle-box')){
+      $(toggleBox).remove();
+    }
     $('.click-menu:not(.'+className+')').css('display', 'none');
     $('.' + className).toggle();
   } 
 
   function drawDriveFiles(jsonData, parentData, name) {
       _selectedData = [];
-      const panel = $('.panel');
+      const panel = $('section .panel');
       let panelStr = `<span class="panel-item on">${name}</span>`;
       const $fileContent = $('.file-content');
       const $oneDriveBtn  = $('.one-drive-button');
@@ -279,10 +283,15 @@
               const {clientX, clientY} = e;
               const array = $('.file-content input[type="checkbox"]');
               let checkCnt = 0;
+              let isChannel = false;
               if (array && array.length > 0) {
                 for (let ii = 0; ii < array.length; ii++) {
                   if (array.eq(ii).is(':checked')) {
-                    checkCnt++;
+                      checkCnt++;
+                      const chanel = document.getElementById(array.eq(ii).val());
+                      if (chanel) {
+                        isChannel = true;
+                      }
                   }
                 }
               }
@@ -290,10 +299,14 @@
               let str = `<div>편집</div>
                 <div>탭으로 설정</div>
                 <div onclick="download()">다운로드</div>
-                <div onclick="deleteItem()">삭제</div>
-                <div onclick="moveItem()">이동</div>
-                <div>복사</div>`;
-              console.log(checkCnt);
+                <div onclick="deleteItem()">삭제</div>`;
+
+              if (!isChannel) {
+                str +=`<div onclick="moveItem('이동')">이동</div>`;
+              }
+
+              str += `<div onclick="moveItem('복사')">복사</div>`;
+              
               if (checkCnt === 1) {
                 str += `<div onclick="nameChange()">이름 바꾸기</div>`;
               }
@@ -410,11 +423,11 @@
       return [images, imageName];
     }
 
-    function moveItem() {
-      
+    function moveItem(text) {
+      const alertTxt = '파일 '+ text;
       const moveArr = $('.file-content div.on input[type="checkbox"]');
       if (moveArr.length === 0) {
-        return alertMessage('파일 이동', '선택 된 파일 정보가 없습니다.');
+        return alertMessage(alertTxt, '선택 된 파일 정보가 없습니다.');
       }
 
       $.ajax({
@@ -429,7 +442,7 @@
             let str = `<div class="modal move" style="display: flex;">
                           <div class="modal-move-box">
                               <div class="left-box">
-                                  <h3 style="padding: 10px;">${moveArr.length}개 항목 이동</h3>
+                                  <h3 style="padding: 10px;">${moveArr.length}개 항목 ${text}</h3>
                                   <div id="move_${oneDriveId}" class="my-file" onclick="setContent('${oneDriveId}', event)"><img src="/static/images/folder-icon.png" alt="폴더 이미지">&nbsp;&nbsp;내 파일</div>
                                   <div class="">
                                       <div></div>
@@ -481,7 +494,7 @@
                                     </div>
                                   </div>
                                   <div class="button-box">
-                                      <div id="move-btn" onclick="moveUpdate()">여기로 이동</div>
+                                      <div id="move-btn" onclick="moveUpdate('${text}')">여기로 ${text}</div>
                                       <div onclick="modalClose('move')">취소</div>
                                   </div>
                               </div>
@@ -499,8 +512,8 @@
       })
     }
 
-    function moveUpdate() {
-
+    function moveUpdate(text) {
+      const alertTitle = '파일 '+ text;
       const selectedDrive = $('.modal-move-box .left-box div.on');
       const siteId = selectedDrive.attr('id');
       const pathArr = $('.modal-move-box .right-box .panel .panel-item');
@@ -511,7 +524,7 @@
         const selectId = siteId.replace('move_', '');
 
         if (selectId === currentId && path === getDrivePath()) {
-          return alertMessage('파일 이동', '대상 경로는 원본 개체와 같을 수 없습니다.');
+          return alertMessage(alertTitle, '대상 경로는 원본 개체와 같을 수 없습니다.');
         }
         callApi('get', '/sites/'+ currentId + getDrivePath(), (itemData)=>{
           if (itemData && itemData.id){
@@ -519,44 +532,140 @@
             callApi('get', '/sites/'+ selectId + path, (jsonData)=>{
               const $selectedItems = $('.file-content div.on');
               const name = [];
+              let str = `<div class="loading-box"><div>파일 생성중입니다...</div>`;
               for (let ii = 0; ii < $selectedItems.length; ii++) {
                 const selectCheck =  $selectedItems.eq(ii).find('input[type="checkbox"]');
                 const selectName = $selectedItems.eq(ii).find('.sp-name');
+                const idArr = [];
                 if ($selectedItems.eq(ii) && selectCheck.length && selectName.length) {
                     name.push({
                       id : selectCheck.val(),
                       name : selectName.text(),
                     });
+                    str += `<div>
+                              <div>
+                                <div>${selectName.text()}</div>
+                                <div class="loading_image_${ii}_box">
+                                  <img class="loading_image_${ii}" src="/static/images/refresh.png" alt="로딩 이미지" width="25" height="25">
+                                </div>
+                              </div>
+                              <div class="loading-gauge-box">
+                                <div>
+                                  <div class="loading-background"></div>  
+                                  <div class="loading-gauge gauge_${ii}"></div>  
+                                </div>
+                                <div><span class="gauge_${ii}_value">0</span> %</div>
+                              </div>
+                            </div>`
                 }
               }
               if (jsonData && jsonData.id) {
+                let uri = '/api/copy-item';
+                let param = {
+                  siteId : currentId,
+                  itemId : itemId,
+                  id : jsonData.id,
+                  name : JSON.stringify(name),
+                  driveId : jsonData.parentReference.driveId,
+                  text : text,
+                }
+                
+                $('.modal-move-box .content').append(str);
                 $.ajax({
                   method : 'post',
-                  url : '/api/move-item',
-                  data : {
-                    siteId : currentId,
-                    itemId : itemId,
-                    id : jsonData.id,
-                    name : JSON.stringify(name),
-                  },
+                  url : uri,
+                  data : param,
+                  global: false,
                   success : (res) => {
-                    // console.log(res);
                     if (res){
                       let message = res.message;
-                      if (res.failItems.length > 0) {
-                        message += '<br>이동 되지 않은 파일 : ';
-                        res.failItems.forEach((fail, idx)=>{
-                          message += fail;
-                          if (res.failItems.length - 1 !== idx) {
-                            message += ',';
-                          }
+                      let failIndexes = [];
+                      if (res.failItems && res.failItems.length) {
+                        res.failItems.forEach((failItem)=>{
+                          let idx = name.findIndex(obj=> obj.name === failItem);
+                          failIndexes.push(idx);
+                          $('.loading_image_' + idx).remove();
+                          $('.loading_image_' + idx +'_box').html('실패');
                         })
                       }
-                      alertMessage('파일 이동', message);
-                      drawMoveItems(selectId, getDrivePath(true));
-                      const selected = $('section .panel-item.on');
-                      selected.removeClass('on');
-                      selected.click();
+                      if (res.locations && res.locations.length > 0) {
+                        function getLoadingState(arr){
+                          Promise.all(res.locations.map((val, idx) => {
+                            if (failIndexes.includes(idx)) {
+                              return null;
+                            }
+                            return $.ajax({url: '/api/loading', global: false, method:'post', data: {url: val}});
+                          }))
+                          .then((values)=>{
+                            if (values && values.length > 0) {
+                              const array = [];
+                              console.log(values);
+                              for (let idx in values) {
+                                const value = values[idx];
+                                console.log(value);
+                                if (value && value.percentageComplete) {
+                                  if (value.percentageComplete !== 100) {
+                                    array.push(res.locations[idx]);
+                                  }
+                                  else {
+                                    $('.loading_image_' + idx).remove();
+                                    $('.loading_image_' + idx +'_box').html('완료됨');
+                                  }
+                                  const percent = value.percentageComplete;
+                                  $('.gauge_'+ idx).css('width', percent+'%');
+                                  $('.gauge_'+ idx + '_value').html(percent);
+                                }
+                              }
+                              if (array.length) {
+                                setTimeout(()=>{
+                                  getLoadingState(array);
+                                }, 2000)
+                              }
+                              else {
+                                if (text === '이동') {
+                                  const checkedArr = [];
+                                  name.forEach((obj)=>{
+                                    checkedArr.push(obj.id);
+                                  });
+                                  $.ajax({
+                                    url: '/api/delete', 
+                                    global: false, 
+                                    method:'post', 
+                                    data: {
+                                      siteId : currentId,
+                                      itemIds : JSON.stringify(checkedArr),
+                                    },
+                                    success: (res)=>{
+                                      console.log();
+                                      if (res && res.success === 'S') {
+                                        alertMessage(alertTitle, message);
+                                        const selected = $('section .panel-item.on');
+                                        selected.removeClass('on');
+                                        selected.click();
+                                        modalClose('move');
+                                      }
+                                    },
+                                    error : (error)=>{
+                                      console.log(error);
+                                    }
+                                  });
+                                }
+                                else {
+                                  alertMessage(alertTitle, message);
+                                  const selected = $('section .panel-item.on');
+                                  selected.removeClass('on');
+                                  selected.click();
+                                  modalClose('move');
+                                }
+                              }
+                            }
+                          })
+                          .catch((error)=>{
+                            console.log(error);
+                          })
+                        }
+                        getLoadingState(res.locations);
+                      }
                     }
                   },
                   error : (error) => {
@@ -565,17 +674,17 @@
                 })
               }
               else {
-                alertMessage('파일 이동', '선택된 그룹 정보를 찾을 수 없습니다.');
+                alertMessage(alertTitle, '선택된 그룹 정보를 찾을 수 없습니다.');
               }
             });
           }
           else {
-            alertMessage('파일 이동', '선택된 그룹 정보를 찾을 수 없습니다.');
+            alertMessage(alertTitle, '선택된 그룹 정보를 찾을 수 없습니다.');
           }
         });
       }
       else {
-        alertMessage('파일 이동', '선택된 그룹 정보를 찾을 수 없습니다.');
+        alertMessage(alertTitle, '선택된 그룹 정보를 찾을 수 없습니다.');
       }
     }
 
@@ -1206,6 +1315,10 @@
     function siteDriveChildrenItems(siteId, path, name, value, event) {
       event.preventDefault();
       event.stopPropagation();
+      const toggleBox = document.getElementsByClassName('toggle-box');
+      if (document.getElementsByClassName('toggle-box')){
+        $(toggleBox).remove();
+      }
       if ($('#all-check').is(':checked')) {
         $('#all-check').prop('checked', false);
       }
@@ -1215,7 +1328,7 @@
       if (value) {
         // $('.tree.group input').prop('checked', true);
         $('input[value="'+value+'"]').prop('checked', false);
-        if ($('.panel').children().text() === name) {
+        if ($('section .panel').children().text() === name) {
           return;
         }
       }
@@ -1229,7 +1342,7 @@
               const panelStr = drawPath(path, siteId, name);
               const $oneDriveBtn = $('.one-drive-button');
               const $fileContent = $('.file-content');
-              const $panel = $('.panel');
+              const $panel = $('section .panel');
               $oneDriveBtn.off('click');
               let text = name;
               if (name !== 'One Drive') {
@@ -1283,25 +1396,6 @@
       return amount;
     }
 
-    // function uploadFiles(itemId) {
-    //   //
-
-    //   $.ajax({
-    //         method: 'post',
-    //         url : "/api-post",
-    //         data: {
-    //           api_uri: '/groups/'+groupId+'/drive/items/'+itemId+'/content',
-    //           scopes : 'Files.ReadWrite',
-    //           param : params,
-    //         },
-    //         success: (res)=> {
-    //           callBackMethod(res, args);
-    //         },
-    //         error: (error)=> {
-    //           console.log(error);
-    //         }
-    //   });
-    // }
 
     function getGroupList() {
       $.ajax({