U4-8636 New Packager - Do not allow a package to be installed multiple times
adds better localization support for installing/uninstalling and validates the installation target
This commit is contained in:
@@ -24,6 +24,15 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
'Failed to get installed packages');
|
||||
},
|
||||
|
||||
validateInstalled: function (name, version) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"packageInstallApiBaseUrl",
|
||||
"ValidateInstalled", { name: name, version: version })),
|
||||
'Failed to validate package ' + name);
|
||||
},
|
||||
|
||||
deleteCreatedPackage: function (packageId) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
|
||||
@@ -17,28 +17,28 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
|
||||
|
||||
|
||||
function FormsController($scope, $route, $cookieStore, packageResource) {
|
||||
function FormsController($scope, $route, $cookieStore, packageResource, localizationService) {
|
||||
$scope.installForms = function(){
|
||||
$scope.state = "Installng package";
|
||||
$scope.state = localizationService.localize("packager_installStateDownloading");
|
||||
packageResource
|
||||
.fetch("CD44CF39-3D71-4C19-B6EE-948E1FAF0525")
|
||||
.then(function(pack) {
|
||||
$scope.state = "importing";
|
||||
$scope.state = localizationService.localize("packager_installStateImporting");
|
||||
return packageResource.import(pack);
|
||||
},
|
||||
$scope.error)
|
||||
.then(function(pack) {
|
||||
$scope.state = "Installing";
|
||||
$scope.state = localizationService.localize("packager_installStateInstalling");
|
||||
return packageResource.installFiles(pack);
|
||||
},
|
||||
$scope.error)
|
||||
.then(function(pack) {
|
||||
$scope.state = "Restarting, please wait...";
|
||||
$scope.state = localizationService.localize("packager_installStateRestarting");
|
||||
return packageResource.installData(pack);
|
||||
},
|
||||
$scope.error)
|
||||
.then(function(pack) {
|
||||
$scope.state = "All done, your browser will now refresh";
|
||||
$scope.state = localizationService.localize("packager_installStateComplete");
|
||||
return packageResource.cleanUp(pack);
|
||||
},
|
||||
$scope.error)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PackagesInstallLocalController($scope, $route, $location, Upload, umbRequestHelper, packageResource, localStorageService, $timeout, $window) {
|
||||
function PackagesInstallLocalController($scope, $route, $location, Upload, umbRequestHelper, packageResource, localStorageService, $timeout, $window, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
vm.state = "upload";
|
||||
@@ -9,7 +9,8 @@
|
||||
vm.localPackage = {};
|
||||
vm.installPackage = installPackage;
|
||||
vm.installState = {
|
||||
status: ""
|
||||
status: "",
|
||||
progress:0
|
||||
};
|
||||
vm.zipFile = {
|
||||
uploadStatus: "idle",
|
||||
@@ -98,7 +99,7 @@
|
||||
}
|
||||
|
||||
function installPackage() {
|
||||
vm.installState.status = "Importing";
|
||||
vm.installState.status = localizationService.localize("packager_installStateImporting");
|
||||
vm.installState.progress = "0";
|
||||
|
||||
//TODO: If any of these fail, will they keep calling the next one?
|
||||
@@ -106,19 +107,19 @@
|
||||
.import(vm.localPackage)
|
||||
.then(function(pack) {
|
||||
vm.installState.progress = "25";
|
||||
vm.installState.status = "Installing...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateInstalling");
|
||||
vm.installState.progress = "50";
|
||||
return packageResource.installFiles(pack);
|
||||
},
|
||||
installError)
|
||||
.then(function(pack) {
|
||||
vm.installState.status = "Restarting, please wait...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateRestarting");
|
||||
vm.installState.progress = "75";
|
||||
return packageResource.installData(pack);
|
||||
},
|
||||
installError)
|
||||
.then(function(pack) {
|
||||
vm.installState.status = "All done, your browser will now refresh, please wait...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateComplete");
|
||||
vm.installState.progress = "100";
|
||||
return packageResource.cleanUp(pack);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PackagesInstalledController($scope, $route, $location, packageResource, $timeout, $window, localStorageService) {
|
||||
function PackagesInstalledController($scope, $route, $location, packageResource, $timeout, $window, localStorageService, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
}
|
||||
|
||||
function uninstallPackage(installedPackage) {
|
||||
vm.installState.status = "Uninstalling package...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateUninstalling");
|
||||
vm.installState.progress = "0";
|
||||
|
||||
packageResource.uninstall(installedPackage.id)
|
||||
.then(function () {
|
||||
|
||||
if (installedPackage.files.length > 0) {
|
||||
vm.installState.status = "All done, your browser will now refresh";
|
||||
vm.installState.status = localizationService.localize("packager_installStateComplete");
|
||||
vm.installState.progress = "100";
|
||||
|
||||
//set this flag so that on refresh it shows the installed packages list
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PackagesRepoController($scope, $route, $location, $timeout, ourPackageRepositoryResource, $q, packageResource, localStorageService) {
|
||||
function PackagesRepoController($scope, $route, $location, $timeout, ourPackageRepositoryResource, $q, packageResource, localStorageService, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
};
|
||||
vm.searchQuery = "";
|
||||
vm.installState = {
|
||||
status: ""
|
||||
status: "",
|
||||
progress: 0,
|
||||
type: "ok"
|
||||
};
|
||||
vm.selectCategory = selectCategory;
|
||||
vm.showPackageDetails = showPackageDetails;
|
||||
@@ -107,11 +109,20 @@
|
||||
|
||||
function showPackageDetails(selectedPackage) {
|
||||
ourPackageRepositoryResource.getDetails(selectedPackage.id)
|
||||
.then(function(pack) {
|
||||
vm.package = pack;
|
||||
vm.packageViewState = "packageDetails";
|
||||
.then(function (pack) {
|
||||
packageResource.validateInstalled(pack.name, pack.latestVersion)
|
||||
.then(function() {
|
||||
//ok, can install
|
||||
vm.package = pack;
|
||||
vm.package.isValid = true;
|
||||
vm.packageViewState = "packageDetails";
|
||||
}, function() {
|
||||
//nope, cannot install
|
||||
vm.package = pack;
|
||||
vm.package.isValid = false;
|
||||
vm.packageViewState = "packageDetails";
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function setPackageViewState(state) {
|
||||
@@ -154,35 +165,42 @@
|
||||
vm.loading = false;
|
||||
vm.localPackage = pack;
|
||||
vm.localPackage.allowed = true;
|
||||
},
|
||||
error);
|
||||
}, function (evt, status, headers, config) {
|
||||
|
||||
if (status == 400) {
|
||||
//it's a validation error
|
||||
vm.installState.type = "error";
|
||||
vm.zipFile.serverErrorMessage = evt.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function error(e, args) {
|
||||
|
||||
//This will return a rejection meaning that the promise change above will stop
|
||||
return $q.reject();
|
||||
}
|
||||
|
||||
function installPackage(selectedPackage) {
|
||||
|
||||
vm.installState.status = "importing...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateImporting");
|
||||
vm.installState.progress = "0";
|
||||
|
||||
packageResource
|
||||
.import(selectedPackage)
|
||||
.then(function(pack) {
|
||||
vm.installState.status = "Installing...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateInstalling");
|
||||
vm.installState.progress = "33";
|
||||
return packageResource.installFiles(pack);
|
||||
},
|
||||
error)
|
||||
.then(function(pack) {
|
||||
vm.installState.status = "Restarting, please wait...";
|
||||
vm.installState.status = localizationService.localize("packager_installStateRestarting");
|
||||
vm.installState.progress = "66";
|
||||
return packageResource.installData(pack);
|
||||
},
|
||||
error)
|
||||
.then(function(pack) {
|
||||
vm.installState.status = "All done, your browser will now refresh";
|
||||
vm.installState.status = localizationService.localize("packager_installStateComplete");
|
||||
vm.installState.progress = "100";
|
||||
return packageResource.cleanUp(pack);
|
||||
},
|
||||
|
||||
@@ -153,7 +153,12 @@
|
||||
<div class="umb-package-details__sidebar">
|
||||
|
||||
<div class="umb-package-details__section">
|
||||
<button class="umb-era-button -blue -full-width" ng-click="vm.downloadPackage(vm.package)">Install package</button>
|
||||
<button class="umb-era-button -blue -full-width"
|
||||
ng-if="vm.package.isValid === true"
|
||||
ng-click="vm.downloadPackage(vm.package)">Install package</button>
|
||||
<div class="umb-info-local-item text-error" ng-if="vm.package.isValid === false">
|
||||
<localize key="packager_packageAlreadyInstalled">The package and version chosen is already installed</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-package-details__section">
|
||||
@@ -310,6 +315,7 @@
|
||||
<strong class="label-text">I accept <a href="{{ vm.localPackage.licenseUrl }}">terms of use</a></strong>
|
||||
</label>
|
||||
<button type="button"
|
||||
ng-if="vm.installState.type !== 'error'"
|
||||
ng-class="{'-inactive' : localPackageForm.$invalid}"
|
||||
ng-disabled="localPackageForm.$invalid"
|
||||
class="umb-era-button -blue flex-inline mt3"
|
||||
@@ -328,8 +334,8 @@
|
||||
<div class="umb-info-local-item text-error" ng-if="!vm.localPackage.isCompatible">
|
||||
This package cannot be installed, it requires a minimum Umbraco version of {{vm.localPackage.umbracoVersion}}
|
||||
</div>
|
||||
|
||||
<div class="umb-info-local-item text-info">
|
||||
|
||||
<div class="umb-info-local-item text-info" ng-class="{'text-info' : vm.installState.type !== 'error'}">
|
||||
<p>{{vm.installState.status}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -783,6 +783,13 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="viewPackageWebsite">View package website</key>
|
||||
<key alias="packageAlreadyInstalled">The package and version chosen is already installed</key>
|
||||
<key alias="targetVersionMismatch">This package cannot be installed, it requires a minimum Umbraco version of %0%</key>
|
||||
<key alias="installStateUninstalling">Uninstalling...</key>
|
||||
<key alias="installStateDownloading">Downloading...</key>
|
||||
<key alias="installStateImporting">Importing...</key>
|
||||
<key alias="installStateInstalling">Installing...</key>
|
||||
<key alias="installStateRestarting">Restarting, please wait...</key>
|
||||
<key alias="installStateComplete">All done, your browser will now refresh, please wait...</key>
|
||||
|
||||
</area>
|
||||
<area alias="paste">
|
||||
<key alias="doNothing">Paste with full formatting (Not recommended)</key>
|
||||
|
||||
@@ -780,6 +780,14 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="packageVersion">Package version</key>
|
||||
<key alias="packageVersionHistory">Package version history</key>
|
||||
<key alias="viewPackageWebsite">View package website</key>
|
||||
<key alias="packageAlreadyInstalled">The package and version chosen is already installed</key>
|
||||
<key alias="targetVersionMismatch">This package cannot be installed, it requires a minimum Umbraco version of %0%</key>
|
||||
<key alias="installStateUninstalling">Uninstalling...</key>
|
||||
<key alias="installStateDownloading">Downloading...</key>
|
||||
<key alias="installStateImporting">Importing...</key>
|
||||
<key alias="installStateInstalling">Installing...</key>
|
||||
<key alias="installStateRestarting">Restarting, please wait...</key>
|
||||
<key alias="installStateComplete">All done, your browser will now refresh, please wait...</key>
|
||||
</area>
|
||||
<area alias="paste">
|
||||
<key alias="doNothing">Paste with full formatting (Not recommended)</key>
|
||||
|
||||
@@ -48,6 +48,21 @@ namespace Umbraco.Web.Editors
|
||||
[UmbracoApplicationAuthorize(Core.Constants.Applications.Developer)]
|
||||
public class PackageInstallController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
/// <summary>
|
||||
/// This checks if this package & version is alraedy installed
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="version"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public IHttpActionResult ValidateInstalled(string name, string version)
|
||||
{
|
||||
var validate = ValidateInstalledInternal(name, version);
|
||||
if (validate == false)
|
||||
return BadRequest();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IHttpActionResult Uninstall(int packageId)
|
||||
{
|
||||
@@ -318,6 +333,34 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateInstalledInternal(string name, string version)
|
||||
{
|
||||
var allInstalled = InstalledPackage.GetAllInstalledPackages();
|
||||
var found = allInstalled.FirstOrDefault(x =>
|
||||
{
|
||||
if (x.Data.Name != name) return false;
|
||||
//match the exact version
|
||||
if (x.Data.Version == version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//now try to compare the versions
|
||||
Version installed;
|
||||
Version selected;
|
||||
if (Version.TryParse(x.Data.Version, out installed) && Version.TryParse(version, out selected))
|
||||
{
|
||||
if (installed >= selected) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found != null)
|
||||
{
|
||||
//this package is already installed
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[FileUploadCleanupFilter(false)]
|
||||
public async Task<LocalPackageInstallModel> UploadLocalPackage()
|
||||
@@ -372,28 +415,11 @@ namespace Umbraco.Web.Editors
|
||||
//Populate the model from the metadata in the package file (zip file)
|
||||
PopulateFromPackageData(model);
|
||||
|
||||
var allInstalled = InstalledPackage.GetAllInstalledPackages();
|
||||
var found = allInstalled.FirstOrDefault(x =>
|
||||
{
|
||||
if (x.Data.Name != model.Name) return false;
|
||||
//match the exact version
|
||||
if (x.Data.Version == model.Version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//now try to compare the versions
|
||||
Version installed;
|
||||
Version selected;
|
||||
if (Version.TryParse(x.Data.Version, out installed) && Version.TryParse(model.Version, out selected))
|
||||
{
|
||||
if (installed >= selected) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found != null)
|
||||
var validate = ValidateInstalledInternal(model.Name, model.Version);
|
||||
|
||||
if (validate == false)
|
||||
{
|
||||
//this package is already installed
|
||||
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
}
|
||||
@@ -442,6 +468,15 @@ namespace Umbraco.Web.Editors
|
||||
//Populate the model from the metadata in the package file (zip file)
|
||||
PopulateFromPackageData(model);
|
||||
|
||||
var validate = ValidateInstalledInternal(model.Name, model.Version);
|
||||
|
||||
if (validate == false)
|
||||
{
|
||||
//this package is already installed
|
||||
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
|
||||
Services.TextService.Localize("packager/packageAlreadyInstalled")));
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace umbraco.presentation.developer.packages
|
||||
/// <summary>
|
||||
/// Summary description for packager.
|
||||
/// </summary>
|
||||
public partial class Installer : UmbracoEnsuredPage
|
||||
[Obsolete("This should not be used and will be removed in v8, this is kept here only for backwards compat reasons, this page should never be rendered/used")]
|
||||
public class Installer : UmbracoEnsuredPage
|
||||
{
|
||||
public Installer()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user