コード例 #1
0
        // used by the html generator
        public List <FileIndexItem> ReadExifAndXmpFromFileAddFilePathHash(List <string> subPathList, List <string> fileHashes = null)
        {
            var fileIndexList = new List <FileIndexItem>();

            for (int i = 0; i < subPathList.Count; i++)
            {
                var subPath = subPathList[i];

                var returnItem  = ReadExifAndXmpFromFile(subPath);
                var imageFormat = ExtensionRolesHelper.GetImageFormat(_iStorage.ReadStream(subPath, 50));

                returnItem.ImageFormat     = imageFormat;
                returnItem.FileName        = Path.GetFileName(subPath);
                returnItem.IsDirectory     = false;
                returnItem.Status          = FileIndexItem.ExifStatus.Ok;
                returnItem.ParentDirectory = FilenamesHelper.GetParentPath(subPath);

                if (fileHashes == null || fileHashes.Count <= i)
                {
                    returnItem.FileHash = new FileHash(_iStorage).GetHashCode(subPath).Key;
                }
                else
                {
                    returnItem.FileHash = fileHashes[i];
                }

                fileIndexList.Add(returnItem);
            }
            return(fileIndexList);
        }
コード例 #2
0
ファイル: QueryFolder.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Show previous en next items in the folder view.
        /// There is equivalent class for prev next in the display view
        /// </summary>
        /// <param name="currentFolder">subPath style</param>
        /// <returns>relative object</returns>
        public RelativeObjects GetNextPrevInFolder(string currentFolder)
        {
            if (currentFolder != "/")
            {
                PathHelper.RemoveLatestSlash(currentFolder);
            }

            // We use breadcrumbs to get the parent folder
            var parentFolderPath = FilenamesHelper.GetParentPath(currentFolder);

            var itemsInSubFolder = QueryGetNextPrevInFolder(parentFolderPath);

            var photoIndexOfSubFolder = itemsInSubFolder.FindIndex(p => p.FilePath == currentFolder);

            var relativeObject = new RelativeObjects();

            if (photoIndexOfSubFolder != itemsInSubFolder.Count - 1 && currentFolder != "/")
            {
                // currentFolder != "/" >= on the home folder you will automatically go to a subfolder
                relativeObject.NextFilePath = itemsInSubFolder[photoIndexOfSubFolder + 1]?.FilePath;
                relativeObject.NextHash     = itemsInSubFolder[photoIndexOfSubFolder + 1]?.FileHash;
            }

            if (photoIndexOfSubFolder >= 1)
            {
                relativeObject.PrevFilePath = itemsInSubFolder[photoIndexOfSubFolder - 1]?.FilePath;
                relativeObject.PrevHash     = itemsInSubFolder[photoIndexOfSubFolder - 1]?.FileHash;
            }

            return(relativeObject);
        }
コード例 #3
0
ファイル: StructureService.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Check if a currentChildFolderBuilder exist in the parentFolderBuilder
        /// </summary>
        /// <param name="parentFolderBuilder">parent folder (subPath style)</param>
        /// <param name="currentChildFolderBuilder">child folder with asterisk</param>
        /// <returns>SubPath without asterisk</returns>
        private StringBuilder MatchChildDirectories(StringBuilder parentFolderBuilder, StringBuilder currentChildFolderBuilder)
        {
            // should return a list of: </2019/10/2019_10_08>
            var childDirectories = _storage.GetDirectories(parentFolderBuilder.ToString()).ToList();

            var matchingFoldersPath = childDirectories.FirstOrDefault(p =>
                                                                      MatchChildFolderSearch(parentFolderBuilder, currentChildFolderBuilder, p)
                                                                      );

            // When a new folder with asterisk is created
            if (matchingFoldersPath == null)
            {
                var defaultValue = RemoveAsteriskFromString(currentChildFolderBuilder);
                // When only using Asterisk in structure
                if (defaultValue == "/")
                {
                    defaultValue = "/default";
                }
                parentFolderBuilder.Append(defaultValue);
                return(parentFolderBuilder);
            }

            // When a regex folder is matched
            var childFolderName =
                PathHelper.PrefixDbSlash(FilenamesHelper.GetFileName(matchingFoldersPath));

            parentFolderBuilder.Append(childFolderName);
            return(parentFolderBuilder);
        }
コード例 #4
0
ファイル: RenameService.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Get the collections items when preflighting
        /// Returns as Tuple
        /// item1: inputFileSubPaths, toFileSubPaths
        /// item2: list of fileIndex Results (which contains only error cases)
        /// </summary>
        /// <param name="inputFileSubPaths">from where to copy (file or folder)</param>
        /// <param name="toFileSubPaths">copy to (file or folder)</param>
        /// <param name="fileIndexResultsList">results list</param>
        /// <param name="collections">enable file collections</param>
        /// <returns>inputFileSubPaths list, toFileSubPaths list and fileIndexResultsList</returns>
        private Tuple <Tuple <string[], string[]>, List <FileIndexItem> > CollectionAddPreflight(
            IReadOnlyList <string> inputFileSubPaths, IReadOnlyList <string> toFileSubPaths,
            List <FileIndexItem> fileIndexResultsList, bool collections)
        {
            if (!collections)
            {
                return(new Tuple <Tuple <string[], string[]>, List <FileIndexItem> >(
                           new Tuple <string[], string[]>(inputFileSubPaths.ToArray(), toFileSubPaths.ToArray()),
                           fileIndexResultsList
                           ));
            }

            var inputCollectionFileSubPaths = new List <string>();
            var toCollectionFileSubPaths    = new List <string>();

            for (var i = 0; i < inputFileSubPaths.Count; i++)
            {
                // When the input is a folder, just copy the array
                if (_iStorage.ExistFolder(inputFileSubPaths[i]))
                {
                    inputCollectionFileSubPaths.Add(inputFileSubPaths[i]);
                    toCollectionFileSubPaths.Add(toFileSubPaths[i]);
                    continue;
                }

                // when it is a file update the 'to paths'
                var collectionPaths = _query.SingleItem(inputFileSubPaths[i],
                                                        null, true, false).FileIndexItem.CollectionPaths;
                inputCollectionFileSubPaths.AddRange(collectionPaths);

                for (var j = 0; j < collectionPaths.Count; j++)
                {
                    var collectionItem = collectionPaths[j];
                    // When moving to a folder
                    if (_iStorage.ExistFolder(toFileSubPaths[i]))
                    {
                        toCollectionFileSubPaths.Add(toFileSubPaths[i]);
                        continue;
                    }

                    var extensionWithoutDot = FilenamesHelper.GetFileExtensionWithoutDot(collectionItem);
                    // when rename-ing the current file, but the other ones are implicit copied
                    if (j == 0)
                    {
                        extensionWithoutDot = FilenamesHelper.GetFileExtensionWithoutDot(toFileSubPaths[i]);
                    }

                    // Rename other sidecar files
                    // From file to Deleted
                    var parentFolder = FilenamesHelper.GetParentPath(toFileSubPaths[i]);
                    var baseName     = FilenamesHelper.GetFileNameWithoutExtension(toFileSubPaths[i]);
                    toCollectionFileSubPaths.Add($"{parentFolder}/{baseName}.{extensionWithoutDot}");
                }
            }

            return(new Tuple <Tuple <string[], string[]>, List <FileIndexItem> >(
                       new Tuple <string[], string[]>(inputCollectionFileSubPaths.ToArray(), toCollectionFileSubPaths.ToArray()),
                       fileIndexResultsList
                       ));
        }
コード例 #5
0
        private IActionResult ReturnThumbnailResult(string f, bool json, ThumbnailSize size)
        {
            Response.Headers.Add("x-image-size", new StringValues(size.ToString()));
            var stream      = _thumbnailStorage.ReadStream(ThumbnailNameHelper.Combine(f, size), 50);
            var imageFormat = ExtensionRolesHelper.GetImageFormat(stream);

            if (imageFormat == ExtensionRolesHelper.ImageFormat.unknown)
            {
                SetExpiresResponseHeadersToZero();
                return(NoContent());                // 204
            }

            // When using the api to check using javascript
            // use the cached version of imageFormat, otherwise you have to check if it deleted
            if (json)
            {
                return(Json("OK"));
            }

            stream = _thumbnailStorage.ReadStream(
                ThumbnailNameHelper.Combine(f, size));

            // thumbs are always in jpeg
            Response.Headers.Add("x-filename", new StringValues(FilenamesHelper.GetFileName(f + ".jpg")));
            return(File(stream, "image/jpeg"));
        }
コード例 #6
0
ファイル: RenameService.cs プロジェクト: qdraw/starsky
 private static string GetFileName(string toFileSubPath, string inputFileSubPath)
 {
     // Needed to create SetFilePath() for item that is copied, not the folder
     // no double slash when moving to root folder
     return(toFileSubPath == "/" ? $"/{FilenamesHelper.GetFileName(inputFileSubPath)}"
                         : $"{toFileSubPath}/{FilenamesHelper.GetFileName(inputFileSubPath)}");
 }
コード例 #7
0
        internal async Task <List <string> > AddParentCacheIfNotExistAsync(IEnumerable <string> updatedPaths)
        {
            var parentDirectoryList = new HashSet <string>();

            foreach (var path in updatedPaths)
            {
                parentDirectoryList.Add(FilenamesHelper.GetParentPath(path));
            }

            var shouldAddParentDirectoriesToCache = parentDirectoryList.Where(parentDirectory =>
                                                                              !_query.CacheGetParentFolder(parentDirectory).Item1).ToList();

            if (!shouldAddParentDirectoriesToCache.Any())
            {
                return(new List <string>());
            }

            var databaseQueryResult = await _query.GetAllObjectsAsync(shouldAddParentDirectoriesToCache);

            _logger.LogInformation("[AddParentCacheIfNotExist] files added to cache " +
                                   string.Join(",", shouldAddParentDirectoriesToCache));

            foreach (var directory in shouldAddParentDirectoriesToCache)
            {
                var byDirectory = databaseQueryResult.Where(p => p.ParentDirectory == directory).ToList();
                _query.AddCacheParentItem(directory, byDirectory);
            }
            return(shouldAddParentDirectoriesToCache);
        }
コード例 #8
0
        private async Task LoopOverSidecarFiles(List <string> subPaths)
        {
            var parentDirectories = new HashSet <string>();
            var xmpSubPaths       = subPaths
                                    .Where(ExtensionRolesHelper.IsExtensionSidecar).ToList();

            foreach (var xmpPath in xmpSubPaths)
            {
                parentDirectories.Add(FilenamesHelper.GetParentPath(xmpPath));
            }

            var itemsInDirectories = new HashSet <FileIndexItem>(
                await _query.GetAllFilesAsync(parentDirectories.ToList()));

            // that is an filepath without extension
            var collectionPath = xmpSubPaths.Select(singlePath
                                                    => $"{FilenamesHelper.GetParentPath(singlePath)}/" +
                                                    FilenamesHelper.GetFileNameWithoutExtension(singlePath)).ToList();

            foreach (var item in itemsInDirectories)
            {
                foreach (var singleCollectionPath in collectionPath)
                {
                    if (item.FilePath.StartsWith(singleCollectionPath) &&
                        !ExtensionRolesHelper.IsExtensionSidecar(item.FilePath))
                    {
                        item.RemoveSidecarExtension("xmp");
                        await _query.UpdateItemAsync(item);
                    }
                }
            }

            Console.WriteLine();
        }
コード例 #9
0
ファイル: StructureService.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Get the output of structure applied on the storage
        /// With the DateTime and fileNameBase applied
        /// </summary>
        /// <param name="parsedStructuredList">parsed object, only needed to apply on the storage</param>
        /// <returns>string with subPath</returns>
        private string ApplyStructureRangeToStorage(List <List <StructureRange> > parsedStructuredList)
        {
            var parentFolderBuilder = new StringBuilder();

            foreach (var subStructureItem in parsedStructuredList)
            {
                var currentChildFolderBuilder = new StringBuilder();
                currentChildFolderBuilder.Append("/");

                foreach (var structureItem in subStructureItem)
                {
                    currentChildFolderBuilder.Append(structureItem.Output);
                }

                var parentFolderSubPath = FilenamesHelper.GetParentPath(parentFolderBuilder.ToString());
                var existParentFolder   = _storage.ExistFolder(parentFolderSubPath);

                // default situation without asterisk or child directory is NOT found
                if (!currentChildFolderBuilder.ToString().Contains("*") || !existParentFolder)
                {
                    var currentChildFolderRemovedAsterisk = RemoveAsteriskFromString(currentChildFolderBuilder);
                    parentFolderBuilder.Append(currentChildFolderRemovedAsterisk);
                    continue;
                }

                parentFolderBuilder =
                    MatchChildDirectories(parentFolderBuilder, currentChildFolderBuilder);
            }
            return(parentFolderBuilder.ToString());
        }
コード例 #10
0
ファイル: RenameService.cs プロジェクト: qdraw/starsky
        private async Task FromFileToDeleted(string inputFileSubPath, string toFileSubPath,
                                             List <FileIndexItem> fileIndexResultsList, List <FileIndexItem> fileIndexItems, DetailView detailView)
        {
            // when trying to rename something wrongs
            var fileName = FilenamesHelper.GetFileName(toFileSubPath);

            if (!FilenamesHelper.IsValidFileName(fileName))
            {
                fileIndexResultsList.Add(new FileIndexItem
                {
                    Status = FileIndexItem.ExifStatus.OperationNotSupported
                });
                return;                 //next
            }

            // from/input cache should be cleared
            var inputParentSubFolder = FilenamesHelper.GetParentPath(inputFileSubPath);

            _query.RemoveCacheParentItem(inputParentSubFolder);

            var toParentSubFolder = FilenamesHelper.GetParentPath(toFileSubPath);

            if (string.IsNullOrEmpty(toParentSubFolder))
            {
                toParentSubFolder = "/";
            }

            // clear cache (to FileSubPath parents)
            _query.RemoveCacheParentItem(toParentSubFolder);

            // Check if the parent folder exist in the database
            await _query.AddParentItemsAsync(toParentSubFolder);

            // Save in database before change on disk
            await SaveToDatabaseAsync(fileIndexItems, fileIndexResultsList,
                                      detailView, toFileSubPath);

            // add folder to file system
            if (!_iStorage.ExistFolder(toParentSubFolder))
            {
                _iStorage.CreateDirectory(toParentSubFolder);
                fileIndexResultsList.Add(new FileIndexItem(toParentSubFolder)
                {
                    Status = FileIndexItem.ExifStatus.Ok
                });
            }

            _iStorage.FileMove(inputFileSubPath, toFileSubPath);
            MoveSidecarFile(inputFileSubPath, toFileSubPath);

            // when renaming a folder it should warn the UI that it should remove the source item
            fileIndexResultsList.Add(new FileIndexItem(inputFileSubPath)
            {
                Status = FileIndexItem.ExifStatus.NotFoundSourceMissing
            });
        }
コード例 #11
0
        public StorageThumbnailFilesystemTest()
        {
            var createNewImage = new CreateAnImage();
            var appSettings    = new AppSettings {
                ThumbnailTempFolder = createNewImage.BasePath
            };

            _thumbnailStorage         = new StorageThumbnailFilesystem(appSettings, new FakeIWebLogger());
            _fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(createNewImage.FileName);
        }
コード例 #12
0
ファイル: StructureService.cs プロジェクト: qdraw/starsky
        /// <summary>
        /// Get the fileName from the structure and ignore the parent folders
        /// Does NOT check if the file already exist
        /// </summary>
        /// <param name="dateTime">DateTime to parse</param>
        /// <param name="fileNameBase">include fileName if requested in structure</param>
        /// <param name="extensionWithoutDot">fileExtension without dot</param>
        /// <returns>filename without starting slash</returns>
        public string ParseFileName(DateTime dateTime,
                                    string fileNameBase        = "",
                                    string extensionWithoutDot = "")
        {
            CheckStructureFormat();
            var fileNameStructure =
                PathHelper.PrefixDbSlash(FilenamesHelper.GetFileName(_structure));
            var parsedStructuredList = ParseStructure(fileNameStructure, dateTime, fileNameBase, extensionWithoutDot);

            return(PathHelper.RemovePrefixDbSlash(ApplyStructureRangeToStorage(parsedStructuredList)));
        }
コード例 #13
0
        public Task <List <FileIndexItem> > GetObjectsByFilePathCollectionAsync(List <string> filePathList)
        {
            var result = new List <FileIndexItem>();

            foreach (var path in filePathList)
            {
                var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(path);
                result.AddRange(_fakeContext.Where(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) &&
                                                   p.FileName.StartsWith(fileNameWithoutExtension)));
            }
            return(Task.FromResult(result));
        }
コード例 #14
0
ファイル: Import.cs プロジェクト: qdraw/starsky
 internal static string AppendIndexerToFilePath(string parentDirectory, string fileName, int index)
 {
     if (index >= 1)
     {
         fileName = string.Concat(
             FilenamesHelper.GetFileNameWithoutExtension(fileName),
             $"_{index}.",
             FilenamesHelper.GetFileExtensionWithoutDot(fileName)
             );
     }
     return(PathHelper.AddSlash(parentDirectory) + PathHelper.RemovePrefixDbSlash(fileName));
 }
コード例 #15
0
ファイル: FakeIImport.cs プロジェクト: qdraw/starsky
        public Task <List <ImportIndexItem> > Preflight(List <string> inputFileFullPaths, ImportSettingsModel importSettings)
        {
            var results = new List <ImportIndexItem>();

            foreach (var inputFileFullPath in inputFileFullPaths)
            {
                // if the item fails
                var importIndexFileError = new ImportIndexItem {
                    FilePath           = "/" + FilenamesHelper.GetFileName(inputFileFullPath),
                    SourceFullFilePath = "~/temp/test",
                    FileHash           = "FAKE",
                    MakeModel          = "added if the item fails",
                    Status             = ImportStatus.FileError
                };

                // Check if extension is correct
                if (!ExtensionRolesHelper.IsExtensionSyncSupported(inputFileFullPath))
                {
                    results.Add(importIndexFileError);
                }

                // Check if the file is correct
                var imageFormat = ExtensionRolesHelper.GetImageFormat(
                    _selectorStorage.Get(SelectorStorage.StorageServices.HostFilesystem)
                    .ReadStream(inputFileFullPath, 160));

                if (!ExtensionRolesHelper.ExtensionSyncSupportedList.Contains($"{imageFormat}"))
                {
                    results.Add(importIndexFileError);
                }

                results.Add(new ImportIndexItem
                {
                    Id = 4,
                    SourceFullFilePath = inputFileFullPath,
                    FilePath           = inputFileFullPath,
                    Status             = ImportStatus.Ok,
                    FileHash           = "FAKE",
                    MakeModel          = "added okay",
                    FileIndexItem      = new FileIndexItem()
                    {
                        FileHash = "FAKE_OK", FilePath = inputFileFullPath
                    }
                });
            }
            PreflightList.AddRange(results);
            return(Task.FromResult(results));
        }
コード例 #16
0
        /// <summary>
        /// this updates the main database item for a sidecar file
        /// </summary>
        /// <param name="xmpSubPath">sidecar file</param>
        /// <param name="directoryWithFileIndexItems">directory where the sidecar is located</param>
        /// <returns>completed task</returns>
        private async Task UpdateSidecarFile(string xmpSubPath, List <FileIndexItem> directoryWithFileIndexItems)
        {
            if (!ExtensionRolesHelper.IsExtensionSidecar(xmpSubPath))
            {
                return;
            }
            var sidecarExt =
                FilenamesHelper.GetFileExtensionWithoutDot(xmpSubPath);

            foreach (var item in
                     directoryWithFileIndexItems.Where(item => !item.SidecarExtensionsList.Contains(sidecarExt)))
            {
                item.AddSidecarExtension(sidecarExt);
                await _query.UpdateItemAsync(item);
            }
        }
コード例 #17
0
        /// <summary>
        /// Uses Cache
        /// </summary>
        /// <param name="inputFilePaths">list of paths</param>
        /// <param name="collections">uses collections </param>
        /// <returns>list with items</returns>
        public async Task <List <FileIndexItem> > GetObjectsByFilePathAsync(List <string> inputFilePaths, bool collections)
        {
            var resultFileIndexItemsList = new List <FileIndexItem>();
            var toQueryPaths             = new List <string>();

            foreach (var path in  inputFilePaths)
            {
                var parentPath = FilenamesHelper.GetParentPath(path);

                var(success, cachedResult) = CacheGetParentFolder(parentPath);

                List <FileIndexItem> item = null;
                switch (collections)
                {
                case false:
                    if (!success)
                    {
                        break;
                    }
                    item = cachedResult.Where(p =>
                                              p.ParentDirectory == parentPath &&
                                              p.FileName == FilenamesHelper.GetFileName(path)).ToList();
                    break;

                case true:
                    if (!success)
                    {
                        break;
                    }
                    item = cachedResult.Where(p =>
                                              p.ParentDirectory == parentPath &&
                                              p.FileCollectionName == FilenamesHelper.GetFileNameWithoutExtension(path)).ToList();
                    break;
                }

                if (!success || !item.Any())
                {
                    toQueryPaths.Add(path);
                    continue;
                }
                resultFileIndexItemsList.AddRange(item);
            }
            var fileIndexItemsList = await GetObjectsByFilePathQuery(toQueryPaths.ToArray(), collections);

            resultFileIndexItemsList.AddRange(fileIndexItemsList);
            return(resultFileIndexItemsList);
        }
コード例 #18
0
        /// <summary>
        /// Sidecar files don't have an own item, but there referenced by file items
        /// in the method xmp files are added to the AddSidecarExtension list.
        /// </summary>
        /// <param name="xmpSubPath">sidecar item</param>
        /// <returns>completed task</returns>
        public async Task UpdateSidecarFile(string xmpSubPath)
        {
            if (!ExtensionRolesHelper.IsExtensionSidecar(xmpSubPath))
            {
                return;
            }

            var parentPath = FilenamesHelper.GetParentPath(xmpSubPath);
            var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(xmpSubPath);

            var directoryWithFileIndexItems = (await
                                               _query.GetAllFilesAsync(parentPath)).Where(
                p => p.ParentDirectory == parentPath &&
                p.FileCollectionName == fileNameWithoutExtension).ToList();

            await UpdateSidecarFile(xmpSubPath, directoryWithFileIndexItems);
        }
コード例 #19
0
        [ProducesResponseType(404)] // not found

        public IActionResult ListSizesByHash(string f)
        {
            // For serving jpeg files
            f = FilenamesHelper.GetFileNameWithoutExtension(f);

            // Restrict the fileHash to letters and digits only
            // I/O function calls should not be vulnerable to path injection attacks
            if (!Regex.IsMatch(f, "^[a-zA-Z0-9_-]+$"))
            {
                return(BadRequest());
            }

            var data = new ThumbnailSizesExistStatusModel {
                TinyMeta   = _thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.TinyMeta)),
                Small      = _thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.Small)),
                Large      = _thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.Large)),
                ExtraLarge = _thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.ExtraLarge))
            };

            // Success has all items (except tinyMeta)
            if (data.Small && data.Large && data.ExtraLarge)
            {
                return(Json(data));
            }

            var sourcePath           = _query.GetSubPathByHash(f);
            var isThumbnailSupported =
                ExtensionRolesHelper.IsExtensionThumbnailSupported(sourcePath);

            switch (isThumbnailSupported)
            {
            case true when !string.IsNullOrEmpty(sourcePath):
                Response.StatusCode = 202;
                return(Json(data));

            case false when !string.IsNullOrEmpty(sourcePath):
                Response.StatusCode = 210;                         // A conflict, that the thumb is not generated yet
                return(Json("Thumbnail is not supported; for example you try to view a raw or video file"));

            default:
                return(NotFound("not in index"));
            }
        }
コード例 #20
0
        /// <summary>
        /// Extractes a <c>tar</c> archive to the specified directory.
        /// </summary>
        /// <param name="stream">The <i>.tar</i> to extract.</param>
        /// <param name="outputDir">Output directory to write the files.</param>
        public void ExtractTar(Stream stream, string outputDir)
        {
            var buffer = new byte[100];

            while (true)
            {
                stream.Read(buffer, 0, 100);
                var name = Encoding.ASCII.GetString(buffer).Trim('\0');
                if (string.IsNullOrEmpty(name) || stream.Position > stream.Length)
                {
                    break;
                }
                stream.Seek(24, SeekOrigin.Current);
                stream.Read(buffer, 0, 12);
                var size = Convert.ToInt64(Encoding.UTF8.GetString(buffer, 0, 12).Trim('\0').Trim(), 8);

                stream.Seek(376L, SeekOrigin.Current);

                var output = $"{outputDir}/{name}";
                if (!_storage.ExistFolder(FilenamesHelper.GetParentPath(output)))
                {
                    _storage.CreateDirectory(FilenamesHelper.GetParentPath(output));
                }
                if (!name.EndsWith("/", StringComparison.InvariantCulture))
                {
                    var str = new MemoryStream();
                    var buf = new byte[size];
                    stream.Read(buf, 0, buf.Length);
                    str.Write(buf, 0, buf.Length);
                    _storage.WriteStreamOpenOrCreate(str, output);
                }

                var pos = stream.Position;

                var offset = 512 - (pos % 512);
                if (offset == 512)
                {
                    offset = 0;
                }

                stream.Seek(offset, SeekOrigin.Current);
            }
        }
コード例 #21
0
        [ProducesResponseType(210)] // raw
        public async Task <IActionResult> ByZoomFactor(
            string f,
            int z           = 0,
            string filePath = "")
        {
            // For serving jpeg files
            f = FilenamesHelper.GetFileNameWithoutExtension(f);

            // Restrict the fileHash to letters and digits only
            // I/O function calls should not be vulnerable to path injection attacks
            if (!Regex.IsMatch(f, "^[a-zA-Z0-9_-]+$"))
            {
                return(BadRequest());
            }

            // Cached view of item
            var sourcePath = await _query.GetSubPathByHashAsync(f);

            if (sourcePath == null)
            {
                if (await _query.GetObjectByFilePathAsync(filePath) == null)
                {
                    return(NotFound("not in index"));
                }
                sourcePath = filePath;
            }

            if (ExtensionRolesHelper.IsExtensionThumbnailSupported(sourcePath))
            {
                var fs1 = _iStorage.ReadStream(sourcePath);

                var fileExt = FilenamesHelper.GetFileExtensionWithoutDot(sourcePath);
                Response.Headers.Add("x-filename", FilenamesHelper.GetFileName(sourcePath));
                return(File(fs1, MimeHelper.GetMimeType(fileExt)));
            }

            Response.StatusCode = 210;     // A conflict, that the thumb is not generated yet
            return(Json("Thumbnail is not supported; for example you try to view a raw file"));
        }
コード例 #22
0
        // For displaying single photo's
        // Display feature only?!
        // input: Name of item by db style path
        // With Caching feature :)

        /// <summary>
        /// SingleItemPath do the query for singleitem + return detailview object
        /// </summary>
        /// <param name="singleItemDbPath"></param>
        /// <param name="colorClassActiveList">list of colorclasses to show, default show all</param>
        /// <param name="enableCollections">enable collections feature > default true</param>
        /// <param name="hideDeleted">do not show deleted files > default true</param>
        /// <returns>view object to show on the page</returns>
        public DetailView SingleItem(
            string singleItemDbPath,
            List <ColorClassParser.Color> colorClassActiveList = null,
            bool enableCollections = true,
            bool hideDeleted       = true,
            SortType sort          = SortType.FileName)
        {
            if (string.IsNullOrWhiteSpace(singleItemDbPath))
            {
                return(null);
            }
            var parentFolder       = FilenamesHelper.GetParentPath(singleItemDbPath);
            var fileIndexItemsList = DisplayFileFolders(
                parentFolder, null, false, false).ToList();

            return(SingleItem(
                       fileIndexItemsList,
                       singleItemDbPath,
                       colorClassActiveList,
                       enableCollections,
                       hideDeleted,
                       sort));
        }
コード例 #23
0
ファイル: UploadController.cs プロジェクト: qdraw/starsky
        internal string GetParentDirectoryFromRequestHeader()
        {
            var to = Request.Headers["to"].ToString();

            if (to == "/")
            {
                return("/");
            }

            // only used for direct import
            if (_iStorage.ExistFolder(FilenamesHelper.GetParentPath(to)) &&
                FilenamesHelper.IsValidFileName(FilenamesHelper.GetFileName(to)))
            {
                Request.Headers["filename"] = FilenamesHelper.GetFileName(to);
                return(FilenamesHelper.GetParentPath(PathHelper.RemoveLatestSlash(to)));
            }
            // ReSharper disable once ConvertIfStatementToReturnStatement
            if (!_iStorage.ExistFolder(PathHelper.RemoveLatestSlash(to)))
            {
                return(null);
            }
            return(PathHelper.RemoveLatestSlash(to));
        }
コード例 #24
0
        private static IOrderedQueryable <FileIndexItem> GetObjectsByFilePathCollectionQuery(ApplicationDbContext context,
                                                                                             IEnumerable <string> filePathList)
        {
            var predicates = new List <Expression <Func <FileIndexItem, bool> > >();

            // ReSharper disable once LoopCanBeConvertedToQuery
            foreach (var path in filePathList)
            {
                var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(path);
                if (string.IsNullOrEmpty(FilenamesHelper.GetFileExtensionWithoutDot(path)))
                {
                    predicates.Add(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) &&
                                   p.FileName == fileNameWithoutExtension);
                    continue;
                }
                predicates.Add(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) &&
                               p.FileName.StartsWith(fileNameWithoutExtension + "."));
            }

            var predicate = PredicateBuilder.OrLoop(predicates);

            return(context.FileIndex.Where(predicate).OrderBy(r => r.FileName));
        }
コード例 #25
0
ファイル: ImportController.cs プロジェクト: qdraw/starsky
        public async Task <IActionResult> FromUrl(string fileUrl, string filename, string structure)
        {
            if (filename == null)
            {
                filename = Base32.Encode(FileHash.GenerateRandomBytes(8)) + ".unknown";
            }

            // I/O function calls should not be vulnerable to path injection attacks
            if (!Regex.IsMatch(filename, "^[a-zA-Z0-9_\\s\\.]+$") || !FilenamesHelper.IsValidFileName(filename))
            {
                return(BadRequest());
            }

            var tempImportFullPath = Path.Combine(_appSettings.TempFolder, filename);
            var importSettings     = new ImportSettingsModel(Request)
            {
                Structure = structure
            };
            var isDownloaded = await _httpClientHelper.Download(fileUrl, tempImportFullPath);

            if (!isDownloaded)
            {
                return(NotFound("'file url' not found or domain not allowed " + fileUrl));
            }

            var importedFiles = await _import.Importer(new List <string> {
                tempImportFullPath
            }, importSettings);

            RemoveTempAndParentStreamFolder(tempImportFullPath);

            if (importedFiles.Count == 0)
            {
                Response.StatusCode = 206;
            }
            return(Json(importedFiles));
        }
コード例 #26
0
ファイル: Import.cs プロジェクト: qdraw/starsky
        private ImportIndexItem ApplyStructure(ImportIndexItem importIndexItem, string overwriteStructure)
        {
            importIndexItem.Structure = _appSettings.Structure;

            // Feature to overwrite structures when importing using a header
            // Overwrite the structure in the ImportIndexItem
            if (!string.IsNullOrWhiteSpace(overwriteStructure))
            {
                importIndexItem.Structure = overwriteStructure;
            }

            var structureService = new StructureService(_subPathStorage, importIndexItem.Structure);

            importIndexItem.FileIndexItem.ParentDirectory = structureService.ParseSubfolders(
                importIndexItem.FileIndexItem.DateTime, importIndexItem.FileIndexItem.FileCollectionName,
                FilenamesHelper.GetFileExtensionWithoutDot(importIndexItem.FileIndexItem.FileName));

            importIndexItem.FileIndexItem.FileName = structureService.ParseFileName(
                importIndexItem.FileIndexItem.DateTime, importIndexItem.FileIndexItem.FileCollectionName,
                FilenamesHelper.GetFileExtensionWithoutDot(importIndexItem.FileIndexItem.FileName));
            importIndexItem.FilePath = importIndexItem.FileIndexItem.FilePath;

            return(importIndexItem);
        }
コード例 #27
0
        [ResponseCache(Duration = 29030400)] // 4 weeks
        public IActionResult ThumbnailSmallOrTinyMeta(string f)
        {
            f = FilenamesHelper.GetFileNameWithoutExtension(f);

            // Restrict the fileHash to letters and digits only
            // I/O function calls should not be vulnerable to path injection attacks
            if (!Regex.IsMatch(f, "^[a-zA-Z0-9_-]+$"))
            {
                return(BadRequest());
            }

            if (_thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.Small)))
            {
                var stream = _thumbnailStorage.ReadStream(ThumbnailNameHelper.Combine(f, ThumbnailSize.Small));
                Response.Headers.TryAdd("x-image-size", new StringValues(ThumbnailSize.Small.ToString()));
                return(File(stream, "image/jpeg"));
            }

            if (_thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.TinyMeta)))
            {
                var stream = _thumbnailStorage.ReadStream(ThumbnailNameHelper.Combine(f, ThumbnailSize.TinyMeta));
                Response.Headers.TryAdd("x-image-size", new StringValues(ThumbnailSize.TinyMeta.ToString()));
                return(File(stream, "image/jpeg"));
            }

            if (!_thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, ThumbnailSize.Large)))
            {
                SetExpiresResponseHeadersToZero();
                return(NotFound("hash not found"));
            }

            var streamDefaultThumbnail = _thumbnailStorage.ReadStream(ThumbnailNameHelper.Combine(f, ThumbnailSize.Large));

            Response.Headers.TryAdd("x-image-size", new StringValues(ThumbnailSize.Large.ToString()));
            return(File(streamDefaultThumbnail, "image/jpeg"));
        }
コード例 #28
0
        /// <summary>
        /// fileIndexItemsList, Create an detailView object
        /// </summary>
        /// <param name="fileIndexItemsList">list of fileIndexItems</param>
        /// <param name="singleItemDbPath">database style path</param>
        /// <param name="colorClassActiveList">list of colorClasses to show, default show all</param>
        /// <param name="enableCollections">enable collections feature > default true</param>
        /// <param name="hideDeleted">do not show deleted files > default true</param>
        /// <returns>view object to show on the page</returns>
        public DetailView SingleItem(
            List <FileIndexItem> fileIndexItemsList,
            string singleItemDbPath,
            List <ColorClassParser.Color> colorClassActiveList = null,
            bool enableCollections = true,
            bool hideDeleted       = true,
            SortType sort          = SortType.FileName)
        {
            // reject empty requests
            if (string.IsNullOrWhiteSpace(singleItemDbPath))
            {
                return(null);
            }
            var parentFolder = FilenamesHelper.GetParentPath(singleItemDbPath);

            // RemoveLatestSlash is for '/' folder
            var fileName = singleItemDbPath.Replace(
                PathHelper.RemoveLatestSlash(parentFolder) + "/", string.Empty);

            // Home has no parent, so return a value
            if (fileName == string.Empty && parentFolder == "/" && GetObjectByFilePath("/") != null)
            {
                return(new DetailView
                {
                    FileIndexItem = GetObjectByFilePath("/"),
                    RelativeObjects = new RelativeObjects(),
                    Breadcrumb = new List <string> {
                        "/"
                    },
                    ColorClassActiveList = colorClassActiveList,
                    IsDirectory = true,
                    SubPath = "/",
                    Collections = enableCollections
                });
            }

            var currentFileIndexItem = fileIndexItemsList.FirstOrDefault(p => p.FileName == fileName);

            // Could be not found or not in directory cache
            if (currentFileIndexItem == null)
            {
                // retry
                currentFileIndexItem = GetObjectByFilePath(singleItemDbPath);
                if (currentFileIndexItem == null)
                {
                    return(null);
                }
                AddCacheItem(currentFileIndexItem);
            }

            // To know when a file is deleted
            if (currentFileIndexItem.Tags.Contains("!delete!"))
            {
                currentFileIndexItem.Status = FileIndexItem.ExifStatus.Deleted;
            }

            if (currentFileIndexItem.IsDirectory == true)
            {
                currentFileIndexItem.CollectionPaths = new List <string> {
                    singleItemDbPath
                };
                return(new DetailView
                {
                    IsDirectory = true,
                    SubPath = singleItemDbPath,
                    FileIndexItem = currentFileIndexItem,
                    Collections = enableCollections,
                });
            }

            if (currentFileIndexItem.Tags.Contains("!delete!"))
            {
                hideDeleted = false;
            }

            var fileIndexItemsForPrevNextList = DisplayFileFolders(
                parentFolder, colorClassActiveList, enableCollections, hideDeleted).ToList();

            var itemResult = new DetailView
            {
                FileIndexItem        = currentFileIndexItem,
                RelativeObjects      = GetNextPrevInSubFolder(currentFileIndexItem, fileIndexItemsForPrevNextList, sort),
                Breadcrumb           = Breadcrumbs.BreadcrumbHelper(singleItemDbPath),
                ColorClassActiveList = colorClassActiveList,
                IsDirectory          = false,
                SubPath     = singleItemDbPath,
                Collections = enableCollections
            };

            // First item is current item
            var collectionPaths = new List <string> {
                singleItemDbPath
            };

            collectionPaths.AddRange(fileIndexItemsList
                                     .Where(p => p.FileCollectionName == currentFileIndexItem.FileCollectionName)
                                     .Select(p => p.FilePath));

            var collectionPathsHashSet = new HashSet <string>(collectionPaths);

            itemResult.FileIndexItem.CollectionPaths = collectionPathsHashSet.ToList();

            return(itemResult);
        }
コード例 #29
0
ファイル: FilenameHelpersTest.cs プロジェクト: qdraw/starsky
        public void FilenamesHelper_GetFileExtensionWithoutDot_NoExtension()
        {
            var result = FilenamesHelper.GetFileExtensionWithoutDot("/test_image");

            Assert.AreEqual(string.Empty, result);
        }
コード例 #30
0
        [ResponseCache(Duration = 29030400)] // 4 weeks
        public IActionResult Thumbnail(
            string f,
            bool isSingleItem = false,
            bool json         = false,
            bool extraLarge   = true)
        {
            // f is Hash
            // isSingleItem => detailView
            // Retry thumbnail => is when you press reset thumbnail
            // json, => to don't waste the users bandwidth.

            // For serving jpeg files
            f = FilenamesHelper.GetFileNameWithoutExtension(f);

            // Get the text before at (@) so replace @2000 with nothing to match  fileHash
            var beforeAt = Regex.Match(f, ".*(?=@)", RegexOptions.None,
                                       TimeSpan.FromSeconds(1)).Value;

            if (!string.IsNullOrEmpty(beforeAt))
            {
                f = beforeAt;
            }

            // Restrict the fileHash to letters and digits only
            // I/O function calls should not be vulnerable to path injection attacks
            if (!Regex.IsMatch(f, "^[a-zA-Z0-9_-]+$"))
            {
                return(BadRequest());
            }

            var preferredSize = ThumbnailSize.ExtraLarge;
            var altSize       = ThumbnailSize.Large;

            if (!extraLarge)
            {
                preferredSize = ThumbnailSize.Large;
                altSize       = ThumbnailSize.ExtraLarge;
            }

            if (_thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, preferredSize)))
            {
                return(ReturnThumbnailResult(f, json, preferredSize));
            }

            if (_thumbnailStorage.ExistFile(ThumbnailNameHelper.Combine(f, altSize)))
            {
                return(ReturnThumbnailResult(f, json, altSize));
            }

            // Cached view of item
            var sourcePath = _query.GetSubPathByHash(f);

            if (sourcePath == null)
            {
                SetExpiresResponseHeadersToZero();
                return(NotFound("not in index"));
            }

            // Need to check again for recently moved files
            if (!_iStorage.ExistFile(sourcePath))
            {
                // remove from cache
                _query.ResetItemByHash(f);
                // query database again
                sourcePath = _query.GetSubPathByHash(f);
                SetExpiresResponseHeadersToZero();
                if (sourcePath == null)
                {
                    return(NotFound("not in index"));
                }
            }

            if (!_iStorage.ExistFile(sourcePath))
            {
                return(NotFound("There is no thumbnail image " + f + " and no source image " +
                                sourcePath));
            }

            if (!isSingleItem)
            {
                // "Photo exist in database but " + "isSingleItem flag is Missing"
                SetExpiresResponseHeadersToZero();
                Response.StatusCode = 202;         // A conflict, that the thumb is not generated yet
                return(Json("Thumbnail is not ready yet"));
            }

            if (ExtensionRolesHelper.IsExtensionThumbnailSupported(sourcePath))
            {
                var fs1 = _iStorage.ReadStream(sourcePath);

                var fileExt  = FilenamesHelper.GetFileExtensionWithoutDot(sourcePath);
                var fileName = HttpUtility.UrlEncode(FilenamesHelper.GetFileName(sourcePath));
                Response.Headers.TryAdd("x-filename", new StringValues(fileName));
                return(File(fs1, MimeHelper.GetMimeType(fileExt)));
            }

            Response.StatusCode = 210;     // A conflict, that the thumb is not generated yet
            return(Json("Thumbnail is not supported; for example you try to view a raw file"));
        }