WebFileServer

Механизм одноразовых ссылок для предоставления доступа к

12/19/2020 11:48:18 PM

Changes

.gitignore 7(+7 -0)

FileServer/SPA/SPA_Build/app_bundle.js 112(+0 -112)

FileServer/SPA/SPA_Build/app_bundle.js.map 1(+0 -1)

FileServer/Web/SPA_Build/app_bundle.js 112(+0 -112)

FileServer/Web/SPA_Build/app_bundle.js.map 1(+0 -1)

Details

.gitignore 7(+7 -0)

diff --git a/.gitignore b/.gitignore
index c058bfe..0bfebad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,10 @@ FileServer/SPA/package-lock.json
 FileServer/AppTests/bin
 FileServer/AppTests/obj
 
+
+FileServer/SPA/SPA_Build/app_bundle.js
+FileServer/SPA/SPA_Build/app_bundle.js.map
+
+**/app_bundle.js
+**/app_bundle.js.map
+
diff --git a/FileServer/BLL/BLL.csproj b/FileServer/BLL/BLL.csproj
index 0ef1e91..446f602 100644
--- a/FileServer/BLL/BLL.csproj
+++ b/FileServer/BLL/BLL.csproj
@@ -60,6 +60,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Base\BaseServices.cs" />
+    <Compile Include="LinkStorage.cs" />
     <Compile Include="Services\FS\FSExplorerServices.cs" />
     <Compile Include="Services\FS\FS_WathcerServices.cs" />
     <Compile Include="Services\Mapper\ExplorerMapper.cs" />
diff --git a/FileServer/BLL/LinkStorage.cs b/FileServer/BLL/LinkStorage.cs
new file mode 100644
index 0000000..255f74a
--- /dev/null
+++ b/FileServer/BLL/LinkStorage.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Collections.Concurrent;
+
+using Model.Entities.Files.FS_Entities;
+
+namespace BLL
+{
+
+    /// <summary>
+    /// Создание одноразовых ссылок на файл.
+    /// Используется для педоставления доступа к файлу с других сервисов (Просмотр документов)
+    /// 
+    /// Текущая реализация может привести к утечке памяти (ссылка удаляется только после обращения к ней)
+    /// </summary>
+    public class LinkStorage
+    {
+        private static readonly ConcurrentDictionary<string, SFile> TmpLinkData 
+            = new ConcurrentDictionary<string, SFile>();
+
+
+        /// <summary>
+        /// Сгенерировать одноразовуй ключ для доступа к файлу
+        /// </summary>
+        /// <param name="file"></param>
+        /// <returns></returns>
+        public string CreateTmpLink(SFile file) 
+        {
+            string key = $"{Guid.NewGuid()}{Guid.NewGuid()}";
+
+            if (!TmpLinkData.TryAdd(key, file)) 
+            {
+                throw new Exception("Данный ключ уже присутсвует коллизия. (В данных условиях не возможно)");
+            }
+
+            return key;
+        }
+
+
+        /// <summary>
+        /// Получить данные о файле по ключу
+        /// </summary>
+        /// <returns></returns>
+        public SFile GetLinkByKey(string key)
+        {
+            if (TmpLinkData.TryRemove(key, out SFile data))
+            {
+                return data;
+            }
+
+            throw new Exception("Не удалось найти указанный ключ");
+        }
+
+
+    }
+}
diff --git a/FileServer/SPA/src/JS/React/Controls/FileExplorer/FileExplorerRow.jsx b/FileServer/SPA/src/JS/React/Controls/FileExplorer/FileExplorerRow.jsx
index bc331e6..7d46664 100644
--- a/FileServer/SPA/src/JS/React/Controls/FileExplorer/FileExplorerRow.jsx
+++ b/FileServer/SPA/src/JS/React/Controls/FileExplorer/FileExplorerRow.jsx
@@ -7,6 +7,7 @@ import BaseControl from '../../BaseControl.jsx'
 import Configuration from '../../../Tools/Configuration'
 import FileExplorerServices from '../../../Services/FileExplorerServices'
 
+import Notification from '../../../Tools/Notification'
 
 import ImageFileFind from '../../../../Images/file-find.png'
 
@@ -20,6 +21,8 @@ export default class FileExplorerRow extends BaseControl {
             Data: this.props.data,
             ShoSelectColumn: this.props.ShoSelectColumn
         };
+
+        this.fileExplorerServices = new FileExplorerServices();
     }
 
     componentWillReceiveProps(nextProps) {
@@ -73,7 +76,36 @@ export default class FileExplorerRow extends BaseControl {
             + id;
 
         //window.open(url, '_blank');
-        debugger;
+        this
+            .fileExplorerServices
+            .CreateTmpLink(id)
+            .then(
+                function (data) {
+
+                    if (!data.Successe)
+                    {
+                        //Popup error
+                        Notification.MesEr(data.ResMessage, 'Ошибка генерация одноразовой ссылки');
+                        return;
+                    }
+
+                    //console.log(data);
+                    //console.log(data.Key);
+
+                    //let u = 'https://view.officeapps.live.com/op/view.aspx?src=' + window.location.origin + '/api/Explorer/GetFileOneLink/' + data.Key;
+                    let u = 'http://docs.google.com/viewer?url=' + window.location.origin + '/api/Explorer/GetFileOneLink/' + data.Key;
+
+                    console.log(u);
+                    debugger;
+
+                    window.open(
+                        u,
+                        '_blank'
+                    );
+                }
+                    .bind(this)
+            );
+
     }
 
     render() {
diff --git a/FileServer/SPA/src/JS/Services/FileExplorerServices.js b/FileServer/SPA/src/JS/Services/FileExplorerServices.js
index 9cf088b..22d3c34 100644
--- a/FileServer/SPA/src/JS/Services/FileExplorerServices.js
+++ b/FileServer/SPA/src/JS/Services/FileExplorerServices.js
@@ -1,8 +1,6 @@
 
 import ApiQuery from '../Tools/ApiQuery'
 
-const URL_download = "api/Explorer/GetFile?ID=";
-
 export default class FileExplorerServices {
     constructor() {
 
@@ -11,13 +9,12 @@ export default class FileExplorerServices {
 
         this.URL_Delete = "api/Explorer/DeleteFile";
         this.URL_Move = "api/Explorer/MoveElement";
-        this.URL_Download = URL_download;
+        this.URL_Download = "api/Explorer/GetFile?ID=";
         this.URL_CreateDirectory = "api/Explorer/CreateDirectory?";
 
+        this.URL_CreateOneLink = "api/Explorer/CreateOneLink";
     }
 
-    static staticURL_Download = URL_download;
-
     async DirectoryGetItemsAsync(ID) {
         let url = this.URL_DirectoryItems + ID;
 
@@ -60,4 +57,12 @@ export default class FileExplorerServices {
                 Name: dirname
             });
     }
+
+    async CreateTmpLink(ID) {
+        return await ApiQuery(
+            this.URL_CreateOneLink + '?ID=' + ID,
+            "GET"
+        );
+    }
+
 }
\ No newline at end of file
diff --git a/FileServer/Web/Config.xml b/FileServer/Web/Config.xml
index 74a3237..3dad11a 100644
--- a/FileServer/Web/Config.xml
+++ b/FileServer/Web/Config.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <ConfigData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-  <LastExportDate>2020-12-19T19:26:22.6586096+04:00</LastExportDate>
+  <LastExportDate>2020-12-19T22:38:20.062325+04:00</LastExportDate>
   <WriteNewRootDir>true</WriteNewRootDir>
   <ClearDBWithStart>true</ClearDBWithStart>
   <RootDirs>
diff --git a/FileServer/Web/Controllers/API/ExplorerController.cs b/FileServer/Web/Controllers/API/ExplorerController.cs
index 725b308..b86d8af 100644
--- a/FileServer/Web/Controllers/API/ExplorerController.cs
+++ b/FileServer/Web/Controllers/API/ExplorerController.cs
@@ -20,6 +20,8 @@ using Model.Entities.Users;
 using BLL.Services;
 using BLL.Services.Mapper;
 using BLL.Services.FS;
+using BLL;
+
 
 namespace Web.Controllers.API
 {
@@ -77,14 +79,35 @@ namespace Web.Controllers.API
              : base(controller, Successe, ResMessage) { }
     }
 
+    public class CreateTmpLinkResult 
+        : BaseApiResult
+    {
+        public string Key { set; get; }
+
+        public CreateTmpLinkResult(
+           Base.BaseController controller,
+           bool Successe,
+           string ResMessage
+           )
+           : base(
+                 controller,
+                 Successe,
+                 ResMessage
+                 )
+        { }
+
+    }
 
     public class ExplorerController : Base.BaseApiController
     {
-        readonly ExplorerMapper ExplorerMapper;
+        private readonly ExplorerMapper ExplorerMapper;
+        private readonly LinkStorage LinkStorage;
+
 
         public ExplorerController()
         {
             ExplorerMapper = new ExplorerMapper(UOW, permissionServices, CurrentUserFunc);
+            LinkStorage = new LinkStorage();
         }
 
 
@@ -156,15 +179,91 @@ namespace Web.Controllers.API
             //#Permission
             if (!permissionServices.CanDownload(CurrentUser, file.Root))
             {
+                return File(
+                    new MemoryStream(), 
+                    "application/octet-stream", 
+                    "CanDownload permission error"
+                    );
+            }
+
+
+            return File(
+                file.Info.Open(FileMode.Open, FileAccess.Read), 
+                "application/octet-stream", 
+                file.Name
+                );
+        }
+
+
+        [HttpGet]
+        public JsonResult CreateOneLink(int ID)
+        {
+            //#Data
+            var file = UOW
+                .Repo_SFile
+                .All_NoTrack
+                .FirstOrDefault(e => e.ID == ID);
+
+            //#Permission
+            if (!permissionServices.CanDownload(CurrentUser, file.Root))
+            {
                 MemoryStream res = new MemoryStream();
 
-                return File(res, "application/octet-stream", "CanDownload permission error");
+
+                return
+                    new CreateTmpLinkResult(this, false, "Ошибка доступа к файлу")
+                    {
+                        ActionName = "CreateOneLink"
+                    }
+                    .ToJson;
             }
 
+            var key = LinkStorage
+                .CreateTmpLink(file);
 
-            return File(file.Info.Open(FileMode.Open, FileAccess.Read), "application/octet-stream", file.Name);
+            return
+                new CreateTmpLinkResult(this, true, "")
+                {
+                    ActionName = "CreateOneLink",
+                    Key = key
+                }
+                .ToJson;
         }
 
+        [HttpGet]
+        public FileResult GetFileOneLink()
+        {
+            try
+            {
+                string key = Request
+                    .Url
+                    .OriginalString
+                    .Split('/')
+                    .Last();
+
+                var file = LinkStorage
+                    .GetLinkByKey(key);
+
+                return File(
+                    file.Info.Open(FileMode.Open, FileAccess.Read),
+                    "application/octet-stream",
+                    file.Name
+                );
+            }
+            catch (Exception ex)
+            {
+                return File(
+                    new MemoryStream(),
+                    "application/octet-stream",
+                    ex.Message + ".txt"
+                    );
+            }
+
+        }
+
+
+
+
         [HttpPost]
         public JsonResult DeleteFile(int ID)
         {
diff --git a/FileServer/Web/Properties/PublishProfiles/FolderProfile.pubxml.user b/FileServer/Web/Properties/PublishProfiles/FolderProfile.pubxml.user
index a2e7ab0..9731fdf 100644
--- a/FileServer/Web/Properties/PublishProfiles/FolderProfile.pubxml.user
+++ b/FileServer/Web/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -16,13 +16,13 @@
       <publishTime>09/10/2013 16:29:20</publishTime>
     </File>
     <File Include="bin/BLL.dll">
-      <publishTime>12/07/2020 12:15:55</publishTime>
+      <publishTime>12/19/2020 23:06:37</publishTime>
     </File>
     <File Include="bin/BLL.dll.config">
       <publishTime>12/06/2020 20:44:13</publishTime>
     </File>
     <File Include="bin/BLL.pdb">
-      <publishTime>12/07/2020 12:15:55</publishTime>
+      <publishTime>12/19/2020 23:06:37</publishTime>
     </File>
     <File Include="bin/EntityFramework.dll">
       <publishTime>10/23/2017 13:15:18</publishTime>
@@ -43,13 +43,13 @@
       <publishTime>07/25/2012 11:48:56</publishTime>
     </File>
     <File Include="bin/Model.dll">
-      <publishTime>12/07/2020 12:15:55</publishTime>
+      <publishTime>12/19/2020 23:06:37</publishTime>
     </File>
     <File Include="bin/Model.dll.config">
       <publishTime>12/06/2020 20:44:19</publishTime>
     </File>
     <File Include="bin/Model.pdb">
-      <publishTime>12/07/2020 12:15:55</publishTime>
+      <publishTime>12/19/2020 23:06:37</publishTime>
     </File>
     <File Include="bin/Newtonsoft.Json.dll">
       <publishTime>04/22/2019 01:06:16</publishTime>
@@ -610,16 +610,16 @@
       <publishTime>11/28/2018 13:04:24</publishTime>
     </File>
     <File Include="bin/Web.dll">
-      <publishTime>12/07/2020 13:10:12</publishTime>
+      <publishTime>12/19/2020 23:06:38</publishTime>
     </File>
     <File Include="bin/Web.pdb">
-      <publishTime>12/07/2020 13:10:12</publishTime>
+      <publishTime>12/19/2020 23:06:38</publishTime>
     </File>
     <File Include="bin/WebGrease.dll">
       <publishTime>01/23/2014 13:57:34</publishTime>
     </File>
     <File Include="Config.xml">
-      <publishTime>12/07/2020 12:44:55</publishTime>
+      <publishTime>12/19/2020 22:38:20</publishTime>
     </File>
     <File Include="Content/1607cd6317843193cd8bbd05654038cd.png">
       <publishTime>08/20/2019 20:25:39</publishTime>
@@ -949,19 +949,22 @@
       <publishTime>07/17/2019 23:51:34</publishTime>
     </File>
     <File Include="SPA_Build/app_bundle.js">
-      <publishTime>12/07/2020 13:09:34</publishTime>
+      <publishTime>12/19/2020 23:07:09</publishTime>
     </File>
     <File Include="SPA_Build/app_bundle.js.map">
-      <publishTime>12/07/2020 13:06:55</publishTime>
+      <publishTime>12/19/2020 23:07:09</publishTime>
+    </File>
+    <File Include="SPA_Build/Images/file-find.png">
+      <publishTime>12/19/2020 23:07:09</publishTime>
     </File>
     <File Include="SPA_Build/Images/Folder.png">
-      <publishTime>12/07/2020 10:44:25</publishTime>
+      <publishTime>12/19/2020 23:07:09</publishTime>
     </File>
     <File Include="SPA_Build/Images/Scan.png">
-      <publishTime>12/07/2020 10:44:25</publishTime>
+      <publishTime>12/19/2020 23:07:09</publishTime>
     </File>
     <File Include="SPA_Build/Images/Update.png">
-      <publishTime>12/07/2020 10:44:25</publishTime>
+      <publishTime>12/19/2020 23:07:09</publishTime>
     </File>
     <File Include="Views/App/Index.cshtml">
       <publishTime>12/07/2020 12:51:19</publishTime>
@@ -994,7 +997,7 @@
       <publishTime>11/23/2020 15:41:42</publishTime>
     </File>
     <File Include="Web.config">
-      <publishTime>12/07/2020 12:15:56</publishTime>
+      <publishTime>12/19/2020 23:07:17</publishTime>
     </File>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/FileServer/Web/SPA_Build/Images/file-find.png b/FileServer/Web/SPA_Build/Images/file-find.png
new file mode 100644
index 0000000..4018fd6
Binary files /dev/null and b/FileServer/Web/SPA_Build/Images/file-find.png differ
diff --git a/FileServer/Web/Web.config b/FileServer/Web/Web.config
index cd0fdd8..97ff8a6 100644
--- a/FileServer/Web/Web.config
+++ b/FileServer/Web/Web.config
@@ -87,6 +87,7 @@
     <modules>
       <remove name="TelemetryCorrelationHttpModule" />
       <add name="TelemetryCorrelationHttpModule" type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation" preCondition="managedHandler" />
+      <!--<add name="OneLinkFileModule" type="Web.Modules.OneLinkFileModule"/>-->
     </modules>
     <rewrite>     
       <rules>
diff --git a/FileServer/Web/Web.csproj b/FileServer/Web/Web.csproj
index 9580f84..0081246 100644
--- a/FileServer/Web/Web.csproj
+++ b/FileServer/Web/Web.csproj
@@ -153,6 +153,7 @@
     <None Include="packages.config" />
     <None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
     <Content Include="SPA_Build\app_bundle.js" />
+    <Content Include="SPA_Build\Images\file-find.png" />
     <Content Include="SPA_Build\Images\Folder.png" />
     <Content Include="SPA_Build\Images\Scan.png" />
     <Content Include="SPA_Build\Images\Update.png" />