PageRenderTime 29ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/web/studio/ASC.Web.Studio/Products/Files/Core/Dao/TeamlabDao/FileDao.cs

https://gitlab.com/rekby-archive/onlyoffice-CommunityServer
C# | 1215 lines | 1021 code | 174 blank | 20 comment | 149 complexity | bb2759857a614051aca1cd85115af5ff MD5 | raw file
  1. /*
  2. *
  3. * (c) Copyright Ascensio System Limited 2010-2021
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. *
  15. */
  16. using System;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using System.Linq;
  20. using System.Linq.Expressions;
  21. using System.Threading.Tasks;
  22. using ASC.Common.Data;
  23. using ASC.Common.Data.Sql;
  24. using ASC.Common.Data.Sql.Expressions;
  25. using ASC.Core;
  26. using ASC.Core.Tenants;
  27. using ASC.ElasticSearch;
  28. using ASC.Web.Core.Files;
  29. using ASC.Web.Files.Classes;
  30. using ASC.Web.Files.Core.Search;
  31. using ASC.Web.Files.Resources;
  32. using ASC.Web.Files.Services.DocumentService;
  33. using ASC.Web.Files.Utils;
  34. using ASC.Web.Studio.Core;
  35. namespace ASC.Files.Core.Data
  36. {
  37. internal class FileDao : AbstractDao, IFileDao
  38. {
  39. private static readonly object syncRoot = new object();
  40. public FileDao(int tenantID, String storageKey)
  41. : base(tenantID, storageKey)
  42. {
  43. }
  44. public void InvalidateCache(object fileId)
  45. {
  46. }
  47. public File GetFile(object fileId)
  48. {
  49. return dbManager
  50. .ExecuteList(GetFileQuery(Exp.Eq("id", fileId) & Exp.Eq("current_version", true)))
  51. .ConvertAll(ToFile)
  52. .SingleOrDefault();
  53. }
  54. public File GetFile(object fileId, int fileVersion)
  55. {
  56. return dbManager
  57. .ExecuteList(GetFileQuery(Exp.Eq("id", fileId) & Exp.Eq("version", fileVersion)))
  58. .ConvertAll(ToFile)
  59. .SingleOrDefault();
  60. }
  61. public File GetFile(object parentId, String title)
  62. {
  63. if (String.IsNullOrEmpty(title)) throw new ArgumentNullException(title);
  64. return dbManager
  65. .ExecuteList(GetFileQuery(Exp.Eq("title", title) & Exp.Eq("current_version", true) & Exp.Eq("folder_id", parentId))
  66. .OrderBy("create_on", true)
  67. .SetMaxResults(1))
  68. .ConvertAll(ToFile)
  69. .FirstOrDefault();
  70. }
  71. public File GetFileStable(object fileId, int fileVersion = -1)
  72. {
  73. var query = GetFileQuery(Exp.Eq("id", fileId)
  74. & Exp.Eq("forcesave", 0))
  75. .OrderBy("version", false)
  76. .SetMaxResults(1);
  77. if (fileVersion >= 0)
  78. {
  79. query.Where(Exp.Le("version", fileVersion));
  80. }
  81. return dbManager
  82. .ExecuteList(query)
  83. .ConvertAll(ToFile)
  84. .SingleOrDefault();
  85. }
  86. public List<File> GetFileHistory(object fileId)
  87. {
  88. var files = dbManager
  89. .ExecuteList(GetFileQuery(Exp.Eq("id", fileId)).OrderBy("version", false))
  90. .ConvertAll(ToFile);
  91. return files;
  92. }
  93. public List<File> GetFiles(IEnumerable<object> fileIds)
  94. {
  95. if (fileIds == null || !fileIds.Any()) return new List<File>();
  96. return dbManager
  97. .ExecuteList(GetFileQuery(Exp.In("id", fileIds) & Exp.Eq("current_version", true)))
  98. .ConvertAll(ToFile);
  99. }
  100. public List<File> GetFilesFiltered(IEnumerable<object> fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent)
  101. {
  102. if (fileIds == null || !fileIds.Any() || filterType == FilterType.FoldersOnly) return new List<File>();
  103. var q = GetFileQuery(Exp.In("id", fileIds) & Exp.Eq("current_version", true), false);
  104. if (!string.IsNullOrEmpty(searchText))
  105. {
  106. List<int> searchIds;
  107. var func = GetFuncForSearch(null, null, filterType, subjectGroup, subjectID, searchText, searchInContent, false);
  108. if (FactoryIndexer<FilesWrapper>.TrySelectIds(s => func(s).In(r => r.Id, fileIds.ToArray()), out searchIds))
  109. {
  110. q.Where(Exp.In("id", searchIds));
  111. }
  112. else
  113. {
  114. q.Where(BuildSearch("title", searchText));
  115. }
  116. }
  117. if (subjectID != Guid.Empty)
  118. {
  119. if (subjectGroup)
  120. {
  121. var users = CoreContext.UserManager.GetUsersByGroup(subjectID).Select(u => u.ID.ToString()).ToArray();
  122. q.Where(Exp.In("create_by", users));
  123. }
  124. else
  125. {
  126. q.Where("create_by", subjectID.ToString());
  127. }
  128. }
  129. switch (filterType)
  130. {
  131. case FilterType.DocumentsOnly:
  132. case FilterType.ImagesOnly:
  133. case FilterType.PresentationsOnly:
  134. case FilterType.SpreadsheetsOnly:
  135. case FilterType.ArchiveOnly:
  136. case FilterType.MediaOnly:
  137. q.Where("category", (int)filterType);
  138. break;
  139. case FilterType.ByExtension:
  140. if (!string.IsNullOrEmpty(searchText))
  141. q.Where(BuildSearch("title", searchText, SqlLike.EndWith));
  142. break;
  143. }
  144. return dbManager
  145. .ExecuteList(q)
  146. .ConvertAll(ToFile);
  147. }
  148. public List<object> GetFiles(object parentId)
  149. {
  150. return dbManager.ExecuteList(
  151. Query("files_file")
  152. .Select("id")
  153. .Where(Exp.Eq("folder_id", parentId) & Exp.Eq("current_version", true)))
  154. .ConvertAll(r => r[0]);
  155. }
  156. public List<File> GetFiles(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false)
  157. {
  158. if (filterType == FilterType.FoldersOnly) return new List<File>();
  159. if (orderBy == null) orderBy = new OrderBy(SortedByType.DateAndTime, false);
  160. var q = GetFileQuery(Exp.Eq("current_version", true) & Exp.Eq("folder_id", parentId));
  161. if (withSubfolders)
  162. {
  163. q = GetFileQuery(Exp.Eq("current_version", true) & Exp.Eq("fft.parent_id", parentId))
  164. .InnerJoin("files_folder_tree fft", Exp.EqColumns("fft.folder_id", "f.folder_id"));
  165. }
  166. if (!string.IsNullOrEmpty(searchText))
  167. {
  168. List<int> searchIds;
  169. var func = GetFuncForSearch(parentId, orderBy, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders);
  170. Expression<Func<Selector<FilesWrapper>, Selector<FilesWrapper>>> expression = s => func(s);
  171. if (FactoryIndexer<FilesWrapper>.TrySelectIds(expression, out searchIds))
  172. {
  173. q.Where(Exp.In("id", searchIds));
  174. }
  175. else
  176. {
  177. q.Where(BuildSearch("title", searchText));
  178. }
  179. }
  180. switch (orderBy.SortedBy)
  181. {
  182. case SortedByType.Author:
  183. q.OrderBy("create_by", orderBy.IsAsc);
  184. break;
  185. case SortedByType.Size:
  186. q.OrderBy("content_length", orderBy.IsAsc);
  187. break;
  188. case SortedByType.AZ:
  189. q.OrderBy("title", orderBy.IsAsc);
  190. break;
  191. case SortedByType.DateAndTime:
  192. q.OrderBy("modified_on", orderBy.IsAsc);
  193. break;
  194. case SortedByType.DateAndTimeCreation:
  195. q.OrderBy("create_on", orderBy.IsAsc);
  196. break;
  197. default:
  198. q.OrderBy("title", true);
  199. break;
  200. }
  201. if (subjectID != Guid.Empty)
  202. {
  203. if (subjectGroup)
  204. {
  205. var users = CoreContext.UserManager.GetUsersByGroup(subjectID).Select(u => u.ID.ToString()).ToArray();
  206. q.Where(Exp.In("create_by", users));
  207. }
  208. else
  209. {
  210. q.Where("create_by", subjectID.ToString());
  211. }
  212. }
  213. switch (filterType)
  214. {
  215. case FilterType.DocumentsOnly:
  216. case FilterType.ImagesOnly:
  217. case FilterType.PresentationsOnly:
  218. case FilterType.SpreadsheetsOnly:
  219. case FilterType.ArchiveOnly:
  220. case FilterType.MediaOnly:
  221. q.Where("category", (int)filterType);
  222. break;
  223. case FilterType.ByExtension:
  224. if (!string.IsNullOrEmpty(searchText))
  225. q.Where(BuildSearch("title", searchText, SqlLike.EndWith));
  226. break;
  227. }
  228. return dbManager
  229. .ExecuteList(q)
  230. .ConvertAll(ToFile);
  231. }
  232. public Stream GetFileStream(File file, long offset)
  233. {
  234. return Global.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file), (int)offset);
  235. }
  236. public Uri GetPreSignedUri(File file, TimeSpan expires)
  237. {
  238. return Global.GetStore().GetPreSignedUri(string.Empty, GetUniqFilePath(file), expires,
  239. new List<String>
  240. {
  241. String.Concat("Content-Disposition:", ContentDispositionUtil.GetHeaderValue(file.Title, withoutBase: true))
  242. });
  243. }
  244. public bool IsSupportedPreSignedUri(File file)
  245. {
  246. return Global.GetStore().IsSupportedPreSignedUri;
  247. }
  248. public Stream GetFileStream(File file)
  249. {
  250. return GetFileStream(file, 0);
  251. }
  252. public async Task<Stream> GetFileStreamAsync(File file)
  253. {
  254. return await Global.GetStore().GetReadStreamAsync(string.Empty, GetUniqFilePath(file), 0);
  255. }
  256. public File SaveFile(File file, Stream fileStream)
  257. {
  258. return SaveFile(file, fileStream, true);
  259. }
  260. public File SaveFile(File file, Stream fileStream, bool checkQuota = true)
  261. {
  262. if (file == null)
  263. {
  264. throw new ArgumentNullException("file");
  265. }
  266. if (checkQuota && SetupInfo.MaxChunkedUploadSize < file.ContentLength)
  267. {
  268. throw FileSizeComment.GetFileSizeException(SetupInfo.MaxChunkedUploadSize);
  269. }
  270. if (CoreContext.Configuration.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
  271. {
  272. if (CoreContext.Configuration.PersonalMaxSpace - Global.GetUserUsedSpace(file.ID == null ? SecurityContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength)
  273. {
  274. throw FileSizeComment.GetPersonalFreeSpaceException(CoreContext.Configuration.PersonalMaxSpace);
  275. }
  276. }
  277. var isNew = false;
  278. List<object> parentFoldersIds;
  279. lock (syncRoot)
  280. {
  281. using (var tx = dbManager.BeginTransaction())
  282. {
  283. if (file.ID == null)
  284. {
  285. file.ID = dbManager.ExecuteScalar<int>(new SqlQuery("files_file").SelectMax("id")) + 1;
  286. file.Version = 1;
  287. file.VersionGroup = 1;
  288. isNew = true;
  289. }
  290. file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
  291. //make lowerCase
  292. file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
  293. file.ModifiedBy = SecurityContext.CurrentAccount.ID;
  294. file.ModifiedOn = TenantUtil.DateTimeNow();
  295. if (file.CreateBy == default(Guid)) file.CreateBy = SecurityContext.CurrentAccount.ID;
  296. if (file.CreateOn == default(DateTime)) file.CreateOn = TenantUtil.DateTimeNow();
  297. dbManager.ExecuteNonQuery(
  298. Update("files_file")
  299. .Set("current_version", false)
  300. .Where("id", file.ID)
  301. .Where("current_version", true));
  302. var sql = Insert("files_file")
  303. .InColumnValue("id", file.ID)
  304. .InColumnValue("version", file.Version)
  305. .InColumnValue("version_group", file.VersionGroup)
  306. .InColumnValue("current_version", true)
  307. .InColumnValue("folder_id", file.FolderID)
  308. .InColumnValue("title", file.Title)
  309. .InColumnValue("content_length", file.ContentLength)
  310. .InColumnValue("category", (int)file.FilterType)
  311. .InColumnValue("create_by", file.CreateBy.ToString())
  312. .InColumnValue("create_on", TenantUtil.DateTimeToUtc(file.CreateOn))
  313. .InColumnValue("modified_by", file.ModifiedBy.ToString())
  314. .InColumnValue("modified_on", TenantUtil.DateTimeToUtc(file.ModifiedOn))
  315. .InColumnValue("converted_type", file.ConvertedType)
  316. .InColumnValue("comment", file.Comment)
  317. .InColumnValue("encrypted", file.Encrypted)
  318. .InColumnValue("forcesave", (int)file.Forcesave)
  319. .InColumnValue("thumb", file.ThumbnailStatus);
  320. dbManager.ExecuteNonQuery(sql);
  321. tx.Commit();
  322. file.PureTitle = file.Title;
  323. parentFoldersIds = dbManager.ExecuteList(
  324. new SqlQuery("files_folder_tree")
  325. .Select("parent_id")
  326. .Where(Exp.Eq("folder_id", file.FolderID))
  327. .OrderBy("level", false)
  328. ).ConvertAll(row => row[0]);
  329. if (parentFoldersIds.Count > 0)
  330. dbManager.ExecuteNonQuery(
  331. Update("files_folder")
  332. .Set("modified_on", TenantUtil.DateTimeToUtc(file.ModifiedOn))
  333. .Set("modified_by", file.ModifiedBy.ToString())
  334. .Where(Exp.In("id", parentFoldersIds)));
  335. if (isNew)
  336. {
  337. RecalculateFilesCount(dbManager, file.FolderID);
  338. }
  339. }
  340. }
  341. if (fileStream != null)
  342. {
  343. try
  344. {
  345. SaveFileStream(file, fileStream);
  346. }
  347. catch (Exception saveException)
  348. {
  349. try
  350. {
  351. if (isNew)
  352. {
  353. var stored = Global.GetStore().IsDirectory(GetUniqFileDirectory(file.ID));
  354. DeleteFile(file.ID, stored);
  355. }
  356. else if (!IsExistOnStorage(file))
  357. {
  358. DeleteVersion(file);
  359. }
  360. }
  361. catch (Exception deleteException)
  362. {
  363. throw new Exception(saveException.Message, deleteException);
  364. }
  365. throw;
  366. }
  367. }
  368. FactoryIndexer<FilesWrapper>.IndexAsync(FilesWrapper.GetFilesWrapper(file, parentFoldersIds));
  369. return GetFile(file.ID);
  370. }
  371. public File ReplaceFileVersion(File file, Stream fileStream)
  372. {
  373. if (file == null) throw new ArgumentNullException("file");
  374. if (file.ID == null) throw new ArgumentException("No file id or folder id toFolderId determine provider");
  375. if (SetupInfo.MaxChunkedUploadSize < file.ContentLength)
  376. {
  377. throw FileSizeComment.GetFileSizeException(SetupInfo.MaxChunkedUploadSize);
  378. }
  379. if (CoreContext.Configuration.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
  380. {
  381. if (CoreContext.Configuration.PersonalMaxSpace - Global.GetUserUsedSpace(file.ID == null ? SecurityContext.CurrentAccount.ID : file.CreateBy) < file.ContentLength)
  382. {
  383. throw FileSizeComment.GetPersonalFreeSpaceException(CoreContext.Configuration.PersonalMaxSpace);
  384. }
  385. }
  386. List<object> parentFoldersIds;
  387. lock (syncRoot)
  388. {
  389. using (var tx = dbManager.BeginTransaction())
  390. {
  391. file.Title = Global.ReplaceInvalidCharsAndTruncate(file.Title);
  392. //make lowerCase
  393. file.Title = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetFileExtension(file.Title));
  394. file.ModifiedBy = SecurityContext.CurrentAccount.ID;
  395. file.ModifiedOn = TenantUtil.DateTimeNow();
  396. if (file.CreateBy == default(Guid)) file.CreateBy = SecurityContext.CurrentAccount.ID;
  397. if (file.CreateOn == default(DateTime)) file.CreateOn = TenantUtil.DateTimeNow();
  398. var sql = Update("files_file")
  399. .Set("version", file.Version)
  400. .Set("version_group", file.VersionGroup)
  401. .Set("folder_id", file.FolderID)
  402. .Set("title", file.Title)
  403. .Set("content_length", file.ContentLength)
  404. .Set("category", (int)file.FilterType)
  405. .Set("create_by", file.CreateBy.ToString())
  406. .Set("create_on", TenantUtil.DateTimeToUtc(file.CreateOn))
  407. .Set("modified_by", file.ModifiedBy.ToString())
  408. .Set("modified_on", TenantUtil.DateTimeToUtc(file.ModifiedOn))
  409. .Set("converted_type", file.ConvertedType)
  410. .Set("comment", file.Comment)
  411. .Set("encrypted", file.Encrypted)
  412. .Set("forcesave", (int)file.Forcesave)
  413. .Set("thumb", file.ThumbnailStatus)
  414. .Where("id", file.ID)
  415. .Where("version", file.Version);
  416. dbManager.ExecuteNonQuery(sql);
  417. tx.Commit();
  418. file.PureTitle = file.Title;
  419. parentFoldersIds = dbManager.ExecuteList(
  420. new SqlQuery("files_folder_tree")
  421. .Select("parent_id")
  422. .Where(Exp.Eq("folder_id", file.FolderID))
  423. .OrderBy("level", false)
  424. ).ConvertAll(row => row[0]);
  425. if (parentFoldersIds.Count > 0)
  426. dbManager.ExecuteNonQuery(
  427. Update("files_folder")
  428. .Set("modified_on", TenantUtil.DateTimeToUtc(file.ModifiedOn))
  429. .Set("modified_by", file.ModifiedBy.ToString())
  430. .Where(Exp.In("id", parentFoldersIds)));
  431. }
  432. }
  433. if (fileStream != null)
  434. {
  435. try
  436. {
  437. DeleteVersionStream(file);
  438. SaveFileStream(file, fileStream);
  439. }
  440. catch
  441. {
  442. if (!IsExistOnStorage(file))
  443. {
  444. DeleteVersion(file);
  445. }
  446. throw;
  447. }
  448. }
  449. FactoryIndexer<FilesWrapper>.IndexAsync(FilesWrapper.GetFilesWrapper(file, parentFoldersIds));
  450. return GetFile(file.ID);
  451. }
  452. private void DeleteVersion(File file)
  453. {
  454. if (file == null
  455. || file.ID == null
  456. || file.Version <= 1) return;
  457. dbManager.ExecuteNonQuery(
  458. Delete("files_file")
  459. .Where("id", file.ID)
  460. .Where("version", file.Version));
  461. dbManager.ExecuteNonQuery(
  462. Update("files_file")
  463. .Set("current_version", true)
  464. .Where("id", file.ID)
  465. .Where("version", file.Version - 1));
  466. }
  467. private static void DeleteVersionStream(File file)
  468. {
  469. Global.GetStore().DeleteDirectory(GetUniqFileVersionPath(file.ID, file.Version));
  470. }
  471. private static void SaveFileStream(File file, Stream stream)
  472. {
  473. Global.GetStore().Save(string.Empty, GetUniqFilePath(file), stream, file.Title);
  474. }
  475. public void DeleteFile(object fileId)
  476. {
  477. DeleteFile(fileId, true);
  478. }
  479. private void DeleteFile(object fileId, bool deleteFolder)
  480. {
  481. if (fileId == null) return;
  482. using (var tx = dbManager.BeginTransaction())
  483. {
  484. var fromFolders = dbManager
  485. .ExecuteList(Query("files_file").Select("folder_id").Where("id", fileId).GroupBy("id"))
  486. .ConvertAll(r => r[0]);
  487. dbManager.ExecuteNonQuery(Delete("files_file").Where("id", fileId));
  488. dbManager.ExecuteNonQuery(Delete("files_tag_link").Where("entry_id", fileId.ToString()).Where("entry_type", (int)FileEntryType.File));
  489. var tagsToRemove = dbManager.ExecuteList(
  490. Query("files_tag tbl_ft ")
  491. .Select("tbl_ft.id")
  492. .LeftOuterJoin("files_tag_link tbl_ftl", Exp.EqColumns("tbl_ft.tenant_id", "tbl_ftl.tenant_id") &
  493. Exp.EqColumns("tbl_ft.id", "tbl_ftl.tag_id"))
  494. .Where("tbl_ftl.tag_id is null"))
  495. .ConvertAll(r => Convert.ToInt32(r[0]));
  496. dbManager.ExecuteNonQuery(Delete("files_tag").Where(Exp.In("id", tagsToRemove)));
  497. dbManager.ExecuteNonQuery(Delete("files_security").Where("entry_id", fileId.ToString()).Where("entry_type", (int)FileEntryType.File));
  498. tx.Commit();
  499. fromFolders.ForEach(folderId => RecalculateFilesCount(dbManager, folderId));
  500. }
  501. if (deleteFolder)
  502. DeleteFolder(fileId);
  503. FactoryIndexer<FilesWrapper>.DeleteAsync(new FilesWrapper { Id = (int)fileId });
  504. }
  505. public bool IsExist(String title, object folderId)
  506. {
  507. var fileCount = dbManager.ExecuteScalar<int>(
  508. Query("files_file")
  509. .SelectCount()
  510. .Where("title", title)
  511. .Where("folder_id", folderId)
  512. .Where("current_version", true));
  513. return fileCount != 0;
  514. }
  515. public object MoveFile(object fileId, object toFolderId)
  516. {
  517. if (fileId == null) return null;
  518. using (var tx = dbManager.BeginTransaction())
  519. {
  520. var fromFolders = dbManager
  521. .ExecuteList(Query("files_file").Select("folder_id").Where("id", fileId).GroupBy("id"))
  522. .ConvertAll(r => r[0]);
  523. var sql = Update("files_file")
  524. .Set("folder_id", toFolderId)
  525. .Where("id", fileId);
  526. if (Global.FolderTrash.Equals(toFolderId))
  527. {
  528. sql
  529. .Set("modified_by", SecurityContext.CurrentAccount.ID.ToString())
  530. .Set("modified_on", DateTime.UtcNow);
  531. }
  532. dbManager.ExecuteNonQuery(sql);
  533. tx.Commit();
  534. fromFolders.ForEach(folderId => RecalculateFilesCount(dbManager, folderId));
  535. RecalculateFilesCount(dbManager, toFolderId);
  536. }
  537. var parentFoldersIds = dbManager.ExecuteList(
  538. new SqlQuery("files_folder_tree")
  539. .Select("parent_id")
  540. .Where(Exp.Eq("folder_id", toFolderId))
  541. .OrderBy("level", false)
  542. ).ConvertAll(row => row[0]);
  543. FactoryIndexer<FilesWrapper>.Update(
  544. new FilesWrapper()
  545. {
  546. Id = (int)fileId,
  547. Folders = parentFoldersIds.Select(r => new FilesFoldersWrapper() { FolderId = r.ToString() }).ToList(),
  548. },
  549. UpdateAction.Replace,
  550. w => w.Folders);
  551. return fileId;
  552. }
  553. public File CopyFile(object fileId, object toFolderId)
  554. {
  555. var file = GetFile(fileId);
  556. if (file != null)
  557. {
  558. var copy = new File
  559. {
  560. FileStatus = file.FileStatus,
  561. FolderID = toFolderId,
  562. Title = file.Title,
  563. ConvertedType = file.ConvertedType,
  564. Comment = FilesCommonResource.CommentCopy,
  565. Encrypted = file.Encrypted,
  566. };
  567. using (var stream = GetFileStream(file))
  568. {
  569. copy.ContentLength = stream.CanSeek ? stream.Length : file.ContentLength;
  570. copy = SaveFile(copy, stream);
  571. }
  572. if (file.ThumbnailStatus == Thumbnail.Created)
  573. {
  574. using (var thumbnail = GetThumbnail(file))
  575. {
  576. SaveThumbnail(copy, thumbnail);
  577. }
  578. copy.ThumbnailStatus = Thumbnail.Created;
  579. }
  580. return copy;
  581. }
  582. return null;
  583. }
  584. public object FileRename(File file, string newTitle)
  585. {
  586. newTitle = Global.ReplaceInvalidCharsAndTruncate(newTitle);
  587. dbManager.ExecuteNonQuery(
  588. Update("files_file")
  589. .Set("title", newTitle)
  590. .Set("modified_on", DateTime.UtcNow)
  591. .Set("modified_by", SecurityContext.CurrentAccount.ID.ToString())
  592. .Where("id", file.ID)
  593. .Where("current_version", true));
  594. return file.ID;
  595. }
  596. public string UpdateComment(object fileId, int fileVersion, string comment)
  597. {
  598. comment = comment ?? string.Empty;
  599. comment = comment.Substring(0, Math.Min(comment.Length, 255));
  600. dbManager.ExecuteNonQuery(
  601. Update("files_file")
  602. .Set("comment", comment)
  603. .Where("id", fileId)
  604. .Where("version", fileVersion));
  605. return comment;
  606. }
  607. public void CompleteVersion(object fileId, int fileVersion)
  608. {
  609. dbManager.ExecuteNonQuery(
  610. Update("files_file")
  611. .Set("version_group = version_group + 1")
  612. .Where("id", fileId)
  613. .Where(Exp.Gt("version", fileVersion)));
  614. }
  615. public void ContinueVersion(object fileId, int fileVersion)
  616. {
  617. using (var tx = dbManager.BeginTransaction())
  618. {
  619. var versionGroup =
  620. dbManager.ExecuteScalar<int>(
  621. Query("files_file")
  622. .Select("version_group")
  623. .Where("id", fileId)
  624. .Where("version", fileVersion)
  625. .GroupBy("id"));
  626. dbManager.ExecuteNonQuery(
  627. Update("files_file")
  628. .Set("version_group = version_group - 1")
  629. .Where("id", fileId)
  630. .Where(Exp.Gt("version", fileVersion))
  631. .Where(Exp.Gt("version_group", versionGroup)));
  632. tx.Commit();
  633. }
  634. }
  635. public bool UseTrashForRemove(File file)
  636. {
  637. return file.RootFolderType != FolderType.TRASH && file.RootFolderType != FolderType.Privacy;
  638. }
  639. public static String GetUniqFileDirectory(object fileIdObject)
  640. {
  641. if (fileIdObject == null) throw new ArgumentNullException("fileIdObject");
  642. var fileIdInt = Convert.ToInt32(Convert.ToString(fileIdObject));
  643. return string.Format("folder_{0}/file_{1}", (fileIdInt / 1000 + 1) * 1000, fileIdInt);
  644. }
  645. public static String GetUniqFilePath(File file)
  646. {
  647. return file != null
  648. ? GetUniqFilePath(file, "content" + FileUtility.GetFileExtension(file.PureTitle))
  649. : null;
  650. }
  651. public static String GetUniqFilePath(File file, string fileTitle)
  652. {
  653. return file != null
  654. ? string.Format("{0}/{1}", GetUniqFileVersionPath(file.ID, file.Version), fileTitle)
  655. : null;
  656. }
  657. public static String GetUniqFileVersionPath(object fileIdObject, int version)
  658. {
  659. return fileIdObject != null
  660. ? string.Format("{0}/v{1}", GetUniqFileDirectory(fileIdObject), version)
  661. : null;
  662. }
  663. private void RecalculateFilesCount(IDbManager db, object folderId)
  664. {
  665. db.ExecuteNonQuery(GetRecalculateFilesCountUpdate(folderId));
  666. }
  667. #region chunking
  668. public ChunkedUploadSession CreateUploadSession(File file, long contentLength)
  669. {
  670. return ChunkedUploadSessionHolder.CreateUploadSession(file, contentLength);
  671. }
  672. public File UploadChunk(ChunkedUploadSession uploadSession, Stream stream, long chunkLength)
  673. {
  674. if (!uploadSession.UseChunks)
  675. {
  676. using (var streamToSave = ChunkedUploadSessionHolder.UploadSingleChunk(uploadSession, stream, chunkLength))
  677. {
  678. if (streamToSave != Stream.Null)
  679. {
  680. uploadSession.File = SaveFile(GetFileForCommit(uploadSession), streamToSave, uploadSession.CheckQuota);
  681. }
  682. }
  683. return uploadSession.File;
  684. }
  685. ChunkedUploadSessionHolder.UploadChunk(uploadSession, stream, chunkLength);
  686. if (uploadSession.BytesUploaded == uploadSession.BytesTotal)
  687. {
  688. uploadSession.File = FinalizeUploadSession(uploadSession);
  689. }
  690. return uploadSession.File;
  691. }
  692. private File FinalizeUploadSession(ChunkedUploadSession uploadSession)
  693. {
  694. ChunkedUploadSessionHolder.FinalizeUploadSession(uploadSession);
  695. var file = GetFileForCommit(uploadSession);
  696. SaveFile(file, null, uploadSession.CheckQuota);
  697. ChunkedUploadSessionHolder.Move(uploadSession, GetUniqFilePath(file));
  698. return file;
  699. }
  700. public void AbortUploadSession(ChunkedUploadSession uploadSession)
  701. {
  702. ChunkedUploadSessionHolder.AbortUploadSession(uploadSession);
  703. }
  704. private File GetFileForCommit(ChunkedUploadSession uploadSession)
  705. {
  706. if (uploadSession.File.ID != null)
  707. {
  708. var file = GetFile(uploadSession.File.ID);
  709. if (!uploadSession.KeepVersion) {
  710. file.Version++;
  711. }
  712. file.ContentLength = uploadSession.BytesTotal;
  713. file.ConvertedType = null;
  714. file.Comment = FilesCommonResource.CommentUpload;
  715. file.Encrypted = uploadSession.Encrypted;
  716. file.ThumbnailStatus = Thumbnail.Waiting;
  717. return file;
  718. }
  719. return new File
  720. {
  721. FolderID = uploadSession.File.FolderID,
  722. Title = uploadSession.File.Title,
  723. ContentLength = uploadSession.BytesTotal,
  724. Comment = FilesCommonResource.CommentUpload,
  725. Encrypted = uploadSession.Encrypted,
  726. };
  727. }
  728. #endregion
  729. #region Only in TMFileDao
  730. public void ReassignFiles(IEnumerable<object> fileIds, Guid newOwnerId)
  731. {
  732. dbManager.ExecuteNonQuery(
  733. Update("files_file")
  734. .Set("create_by", newOwnerId.ToString())
  735. .Where(Exp.In("id", fileIds))
  736. .Where("current_version", true));
  737. }
  738. public List<File> GetFiles(IEnumerable<object> parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent)
  739. {
  740. if (parentIds == null || !parentIds.Any() || filterType == FilterType.FoldersOnly) return new List<File>();
  741. var q = GetFileQuery(Exp.Eq("current_version", true) & Exp.In("fft.parent_id", parentIds))
  742. .InnerJoin("files_folder_tree fft", Exp.EqColumns("fft.folder_id", "f.folder_id"));
  743. if (!string.IsNullOrEmpty(searchText))
  744. {
  745. List<int> searchIds;
  746. var func = GetFuncForSearch(null, null, filterType, subjectGroup, subjectID, searchText, searchInContent, false);
  747. if (FactoryIndexer<FilesWrapper>.TrySelectIds(s => func(s), out searchIds))
  748. {
  749. q.Where(Exp.In("id", searchIds));
  750. }
  751. else
  752. {
  753. q.Where(BuildSearch("title", searchText));
  754. }
  755. }
  756. if (subjectID != Guid.Empty)
  757. {
  758. if (subjectGroup)
  759. {
  760. var users = CoreContext.UserManager.GetUsersByGroup(subjectID).Select(u => u.ID.ToString()).ToArray();
  761. q.Where(Exp.In("create_by", users));
  762. }
  763. else
  764. {
  765. q.Where("create_by", subjectID.ToString());
  766. }
  767. }
  768. switch (filterType)
  769. {
  770. case FilterType.DocumentsOnly:
  771. case FilterType.ImagesOnly:
  772. case FilterType.PresentationsOnly:
  773. case FilterType.SpreadsheetsOnly:
  774. case FilterType.ArchiveOnly:
  775. case FilterType.MediaOnly:
  776. q.Where("category", (int)filterType);
  777. break;
  778. case FilterType.ByExtension:
  779. if (!string.IsNullOrEmpty(searchText))
  780. q.Where(BuildSearch("title", searchText, SqlLike.EndWith));
  781. break;
  782. }
  783. return dbManager
  784. .ExecuteList(q)
  785. .ConvertAll(ToFile);
  786. }
  787. public IEnumerable<File> Search(String searchText, bool bunch)
  788. {
  789. List<int> ids;
  790. if (FactoryIndexer<FilesWrapper>.TrySelectIds(s => s.MatchAll(searchText), out ids))
  791. {
  792. return dbManager
  793. .ExecuteList(GetFileQuery(Exp.In("id", ids) & Exp.Eq("current_version", true)))
  794. .ConvertAll(ToFile)
  795. .Where(
  796. f =>
  797. bunch
  798. ? f.RootFolderType == FolderType.BUNCH
  799. : f.RootFolderType == FolderType.USER || f.RootFolderType == FolderType.COMMON)
  800. .ToList();
  801. }
  802. else
  803. {
  804. var q = GetFileQuery(Exp.Eq("current_version", true) & BuildSearch("title", searchText));
  805. return dbManager
  806. .ExecuteList(q)
  807. .ConvertAll(ToFile)
  808. .Where(f =>
  809. bunch
  810. ? f.RootFolderType == FolderType.BUNCH
  811. : f.RootFolderType == FolderType.USER || f.RootFolderType == FolderType.COMMON)
  812. .ToList();
  813. }
  814. }
  815. private static void DeleteFolder(object fileId)
  816. {
  817. Global.GetStore().DeleteDirectory(GetUniqFileDirectory(fileId));
  818. }
  819. public bool IsExistOnStorage(File file)
  820. {
  821. return Global.GetStore().IsFile(GetUniqFilePath(file));
  822. }
  823. public async Task<bool> IsExistOnStorageAsync(File file)
  824. {
  825. return await Global.GetStore().IsFileAsync(string.Empty, GetUniqFilePath(file));
  826. }
  827. private const string DiffTitle = "diff.zip";
  828. public void SaveEditHistory(File file, string changes, Stream differenceStream)
  829. {
  830. if (file == null) throw new ArgumentNullException("file");
  831. if (string.IsNullOrEmpty(changes)) throw new ArgumentNullException("changes");
  832. if (differenceStream == null) throw new ArgumentNullException("differenceStream");
  833. changes = changes.Trim();
  834. dbManager.ExecuteNonQuery(
  835. Update("files_file")
  836. .Set("changes", changes)
  837. .Where("id", file.ID)
  838. .Where("version", file.Version));
  839. Global.GetStore().Save(string.Empty, GetUniqFilePath(file, DiffTitle), differenceStream, DiffTitle);
  840. }
  841. public List<EditHistory> GetEditHistory(object fileId, int fileVersion = 0)
  842. {
  843. var query = Query("files_file")
  844. .Select("id")
  845. .Select("version")
  846. .Select("version_group")
  847. .Select("modified_on")
  848. .Select("modified_by")
  849. .Select("changes")
  850. .Select("create_on")
  851. .Where(Exp.Eq("id", fileId))
  852. .Where(Exp.Eq("forcesave", 0))
  853. .OrderBy("version", true);
  854. if (fileVersion > 0)
  855. {
  856. query.Where(Exp.Eq("version", fileVersion));
  857. }
  858. return
  859. dbManager
  860. .ExecuteList(query)
  861. .ConvertAll(r =>
  862. {
  863. var item = new EditHistory
  864. {
  865. ID = Convert.ToInt32(r[0]),
  866. Version = Convert.ToInt32(r[1]),
  867. VersionGroup = Convert.ToInt32(r[2]),
  868. ModifiedOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[3])),
  869. ModifiedBy = new EditHistoryAuthor { Id = (string)r[4] },
  870. ChangesString = (string)r[5],
  871. };
  872. item.Key = DocumentServiceHelper.GetDocKey(item.ID, item.Version, TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[6])));
  873. return item;
  874. });
  875. }
  876. public Stream GetDifferenceStream(File file)
  877. {
  878. return Global.GetStore().GetReadStream(string.Empty, GetUniqFilePath(file, DiffTitle));
  879. }
  880. public bool ContainChanges(object fileId, int fileVersion)
  881. {
  882. return dbManager.ExecuteScalar<int>(
  883. Query("files_file")
  884. .SelectCount()
  885. .Where(Exp.Eq("id", fileId))
  886. .Where(Exp.Eq("version", fileVersion))
  887. .Where(!Exp.Eq("changes", null))) > 0;
  888. }
  889. private const string ThumbnailTitle = "thumb";
  890. public void SaveThumbnail(File file, Stream thumbnail)
  891. {
  892. if (file == null) throw new ArgumentNullException("file");
  893. dbManager.ExecuteNonQuery(
  894. Update("files_file")
  895. .Set("thumb", thumbnail != null ? Thumbnail.Created : file.ThumbnailStatus)
  896. .Where("id", file.ID)
  897. .Where("version", file.Version));
  898. if (thumbnail == null) return;
  899. var thumnailName = ThumbnailTitle + "." + Global.ThumbnailExtension;
  900. Global.GetStore().Save(string.Empty, GetUniqFilePath(file, thumnailName), thumbnail, thumnailName);
  901. }
  902. public Stream GetThumbnail(File file)
  903. {
  904. var thumnailName = ThumbnailTitle + "." + Global.ThumbnailExtension;
  905. var path = GetUniqFilePath(file, thumnailName);
  906. var storage = Global.GetStore();
  907. if (!storage.IsFile(string.Empty, path)) throw new FileNotFoundException();
  908. return storage.GetReadStream(string.Empty, path);
  909. }
  910. public EntryProperties GetProperties(object fileId)
  911. {
  912. var query = Query("files_properties")
  913. .Select("data")
  914. .Where("entry_id", fileId);
  915. return dbManager
  916. .ExecuteList(Query("files_properties")
  917. .Select("data")
  918. .Where(Exp.Eq("entry_id", fileId)))
  919. .ConvertAll(r =>
  920. {
  921. return EntryProperties.Parse((string)r[0]);
  922. })
  923. .SingleOrDefault();
  924. }
  925. public void SaveProperties(object fileId, EntryProperties entryProperties)
  926. {
  927. string data;
  928. if (entryProperties == null
  929. || string.IsNullOrEmpty(data = EntryProperties.Serialize(entryProperties)))
  930. {
  931. dbManager.ExecuteNonQuery(
  932. Delete("files_properties")
  933. .Where("entry_id", fileId));
  934. return;
  935. }
  936. dbManager.ExecuteNonQuery(Insert("files_properties")
  937. .InColumnValue("entry_id", fileId)
  938. .InColumnValue("data", data));
  939. }
  940. #endregion
  941. private File ToFile(object[] r)
  942. {
  943. var result = new File
  944. {
  945. ID = Convert.ToInt32(r[0]),
  946. Title = (String)r[1],
  947. FolderID = Convert.ToInt32(r[2]),
  948. CreateOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[3])),
  949. CreateBy = new Guid((string)r[4]),
  950. Version = Convert.ToInt32(r[5]),
  951. VersionGroup = Convert.ToInt32(r[6]),
  952. ContentLength = Convert.ToInt64(r[7]),
  953. ModifiedOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[8])),
  954. ModifiedBy = new Guid((string)r[9]),
  955. RootFolderType = ParseRootFolderType(r[10]),
  956. RootFolderCreator = ParseRootFolderCreator(r[10]),
  957. RootFolderId = ParseRootFolderId(r[10]),
  958. Shared = Convert.ToBoolean(r[11]),
  959. ConvertedType = (string)r[12],
  960. Comment = (string)r[13],
  961. Encrypted = Convert.ToBoolean(r[14]),
  962. Forcesave = ParseForcesaveType(r[15]),
  963. ThumbnailStatus = (Thumbnail)Enum.Parse(typeof(Thumbnail), r[16].ToString()),
  964. IsFillFormDraft = Convert.ToBoolean(r[17])
  965. };
  966. SetEntryDenyProperties(result, (string)r[18]);
  967. return result;
  968. }
  969. private static ForcesaveType ParseForcesaveType(object v)
  970. {
  971. return v != null
  972. ? (ForcesaveType)Enum.Parse(typeof(ForcesaveType), v.ToString().Substring(0, 1))
  973. : default(ForcesaveType);
  974. }
  975. private Func<Selector<FilesWrapper>, Selector<FilesWrapper>> GetFuncForSearch(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false)
  976. {
  977. return s =>
  978. {
  979. var result = !searchInContent || filterType == FilterType.ByExtension
  980. ? s.Match(r => r.Title, searchText)
  981. : s.MatchAll(searchText);
  982. if (parentId != null)
  983. {
  984. if (withSubfolders)
  985. {
  986. result.In(a => a.Folders.Select(r => r.FolderId), new[] { parentId.ToString() });
  987. }
  988. else
  989. {
  990. result.InAll(a => a.Folders.Select(r => r.FolderId), new[] { parentId.ToString() });
  991. }
  992. }
  993. if (orderBy != null)
  994. {
  995. switch (orderBy.SortedBy)
  996. {
  997. case SortedByType.Author:
  998. result.Sort(r => r.CreateBy, orderBy.IsAsc);
  999. break;
  1000. case SortedByType.Size:
  1001. result.Sort(r => r.ContentLength, orderBy.IsAsc);
  1002. break;
  1003. //case SortedByType.AZ:
  1004. // result.Sort(r => r.Title, orderBy.IsAsc);
  1005. // break;
  1006. case SortedByType.DateAndTime:
  1007. result.Sort(r => r.LastModifiedOn, orderBy.IsAsc);
  1008. break;
  1009. case SortedByType.DateAndTimeCreation:
  1010. result.Sort(r => r.CreateOn, orderBy.IsAsc);
  1011. break;
  1012. }
  1013. }
  1014. if (subjectID != Guid.Empty)
  1015. {
  1016. if (subjectGroup)
  1017. {
  1018. var users = CoreContext.UserManager.GetUsersByGroup(subjectID).Select(u => u.ID.ToString()).ToArray();
  1019. result.In(r => r.CreateBy, users);
  1020. }
  1021. else
  1022. {
  1023. result.Where(r => r.CreateBy, subjectID);
  1024. }
  1025. }
  1026. switch (filterType)
  1027. {
  1028. case FilterType.DocumentsOnly:
  1029. case FilterType.ImagesOnly:
  1030. case FilterType.PresentationsOnly:
  1031. case FilterType.SpreadsheetsOnly:
  1032. case FilterType.ArchiveOnly:
  1033. case FilterType.MediaOnly:
  1034. result.Where(r => r.Category, (int)filterType);
  1035. break;
  1036. }
  1037. return result;
  1038. };
  1039. }
  1040. }
  1041. }