/// <summary> /// Upload single item from the archive into the physical directory /// </summary> /// <param name="archivePath">Path to the archive</param> /// <returns>Uploaded item descriptor</returns> protected virtual IDescriptor UploadSingleItem(string archivePath) { //get path to the plugins directory var pluginsDirectory = _fileProvider.MapPath(NopPluginDefaults.Path); //get path to the themes directory var themesDirectory = string.Empty; if (!string.IsNullOrEmpty(NopPluginDefaults.ThemesPath)) { themesDirectory = _fileProvider.MapPath(NopPluginDefaults.ThemesPath); } IDescriptor descriptor = null; string uploadedItemDirectoryName; using (var archive = ZipFile.OpenRead(archivePath)) { //the archive should contain only one root directory (the plugin one or the theme one) var rootDirectories = archive.Entries.Select(p => p.FullName.Split('/')[0]).Distinct().ToList(); if (rootDirectories.Count != 1) { throw new Exception("The archive should contain only one root plugin or theme directory. " + "For example, Payments.PayPalDirect or DefaultClean. " + $"To upload multiple items, the archive should have the '{NopPluginDefaults.UploadedItemsFileName}' file in the root"); } //get directory name (remove the ending /) uploadedItemDirectoryName = rootDirectories.First(); //try to get descriptor of the uploaded item foreach (var entry in archive.Entries) { //whether it's a plugin descriptor var isPluginDescriptor = entry.FullName .Equals($"{uploadedItemDirectoryName}/{NopPluginDefaults.DescriptionFileName}", StringComparison.InvariantCultureIgnoreCase); //or whether it's a theme descriptor var isThemeDescriptor = entry.FullName .Equals($"{uploadedItemDirectoryName}/{NopPluginDefaults.ThemeDescriptionFileName}", StringComparison.InvariantCultureIgnoreCase); if (!isPluginDescriptor && !isThemeDescriptor) { continue; } using var unzippedEntryStream = entry.Open(); using var reader = new StreamReader(unzippedEntryStream); //whether a plugin is upload if (isPluginDescriptor) { descriptor = PluginDescriptor.GetPluginDescriptorFromText(reader.ReadToEnd()); //ensure that the plugin current version is supported if (!((PluginDescriptor)descriptor).SupportedVersions.Contains(NopVersion.CurrentVersion)) { throw new Exception($"This plugin doesn't support the current version - {NopVersion.CurrentVersion}"); } } //or whether a theme is upload if (isThemeDescriptor) { descriptor = _themeProvider.GetThemeDescriptorFromText(reader.ReadToEnd()); } break; } } if (descriptor == null) { throw new Exception("No descriptor file is found. It should be in the root of the archive."); } if (string.IsNullOrEmpty(uploadedItemDirectoryName)) { throw new Exception($"Cannot get the {(descriptor is PluginDescriptor ? "plugin" : "theme")} directory name"); } //get path to upload var directoryPath = descriptor is PluginDescriptor ? pluginsDirectory : themesDirectory; var pathToUpload = _fileProvider.Combine(directoryPath, uploadedItemDirectoryName); //ensure it's a new directory (e.g. some old files are not required when re-uploading a plugin) //furthermore, zip extract functionality cannot override existing files //but there could deletion issues (related to file locking, etc). In such cases the directory should be deleted manually if (_fileProvider.DirectoryExists(pathToUpload)) { _fileProvider.DeleteDirectory(pathToUpload); } //unzip archive ZipFile.ExtractToDirectory(archivePath, directoryPath); return(descriptor); }
/// <summary> /// Upload multiple items from the archive into the physical directory /// </summary> /// <param name="archivePath">Path to the archive</param> /// <param name="uploadedItems">Uploaded items</param> /// <returns>List of uploaded items descriptor</returns> protected virtual IList <IDescriptor> UploadMultipleItems(string archivePath, IList <UploadedItem> uploadedItems) { //get path to the plugins directory var pluginsDirectory = _fileProvider.MapPath(NopPluginDefaults.Path); //get path to the themes directory var themesDirectory = string.Empty; if (!string.IsNullOrEmpty(NopPluginDefaults.ThemesPath)) { themesDirectory = _fileProvider.MapPath(NopPluginDefaults.ThemesPath); } //get descriptors of items contained in the archive var descriptors = new List <IDescriptor>(); using (var archive = ZipFile.OpenRead(archivePath)) { foreach (var item in uploadedItems) { if (!item.Type.HasValue) { continue; } //ensure that the current version of nopCommerce is supported if (!item.SupportedVersions?.Contains(NopVersion.CurrentVersion) ?? true) { continue; } //the item path should end with a slash var itemPath = $"{item.DirectoryPath?.TrimEnd('/')}/"; //get path to the descriptor entry in the archive var descriptorPath = string.Empty; if (item.Type == UploadedItemType.Plugin) { descriptorPath = $"{itemPath}{NopPluginDefaults.DescriptionFileName}"; } if (item.Type == UploadedItemType.Theme && !string.IsNullOrEmpty(NopPluginDefaults.ThemeDescriptionFileName)) { descriptorPath = $"{itemPath}{NopPluginDefaults.ThemeDescriptionFileName}"; } //try to get the descriptor entry var descriptorEntry = archive.Entries.FirstOrDefault(entry => entry.FullName.Equals(descriptorPath, StringComparison.InvariantCultureIgnoreCase)); if (descriptorEntry == null) { continue; } //try to get descriptor of the uploaded item IDescriptor descriptor = null; using (var unzippedEntryStream = descriptorEntry.Open()) { using var reader = new StreamReader(unzippedEntryStream); //whether a plugin is upload if (item.Type == UploadedItemType.Plugin) { descriptor = PluginDescriptor.GetPluginDescriptorFromText(reader.ReadToEnd()); } //or whether a theme is upload if (item.Type == UploadedItemType.Theme) { descriptor = _themeProvider.GetThemeDescriptorFromText(reader.ReadToEnd()); } } if (descriptor == null) { continue; } //ensure that the plugin current version is supported if (descriptor is PluginDescriptor pluginDescriptor && !pluginDescriptor.SupportedVersions.Contains(NopVersion.CurrentVersion)) { continue; } //get path to upload var uploadedItemDirectoryName = _fileProvider.GetFileName(itemPath.TrimEnd('/')); var pathToUpload = _fileProvider.Combine(item.Type == UploadedItemType.Plugin ? pluginsDirectory : themesDirectory, uploadedItemDirectoryName); //ensure it's a new directory (e.g. some old files are not required when re-uploading a plugin or a theme) //furthermore, zip extract functionality cannot override existing files //but there could deletion issues (related to file locking, etc). In such cases the directory should be deleted manually if (_fileProvider.DirectoryExists(pathToUpload)) { _fileProvider.DeleteDirectory(pathToUpload); } //unzip entries into files var entries = archive.Entries.Where(entry => entry.FullName.StartsWith(itemPath, StringComparison.InvariantCultureIgnoreCase)); foreach (var entry in entries) { //get name of the file var fileName = entry.FullName.Substring(itemPath.Length); if (string.IsNullOrEmpty(fileName)) { continue; } var filePath = _fileProvider.Combine(pathToUpload, fileName); //if it's a folder, we need to create it if (string.IsNullOrEmpty(entry.Name) && !_fileProvider.DirectoryExists(filePath)) { _fileProvider.CreateDirectory(filePath); continue; } var directoryPath = _fileProvider.GetDirectoryName(filePath); //whether the file directory is already exists, otherwise create the new one if (!_fileProvider.DirectoryExists(directoryPath)) { _fileProvider.CreateDirectory(directoryPath); } //unzip entry to the file (ignore directory entries) if (!filePath.Equals($"{directoryPath}\\", StringComparison.InvariantCultureIgnoreCase)) { entry.ExtractToFile(filePath); } } //item is uploaded descriptors.Add(descriptor); } } return(descriptors); }