protected virtual void ValidateEdit(EditValidationResult result)
 {
 }
        async Task<EditValidationResult> ValidateEdit(Stream metadataStream)
        {
            EditValidationResult result = new EditValidationResult();

            JObject metadata = await ServiceHelpers.ReadJObject(metadataStream);
            if (metadata != null)
            {
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "namespace", result.Errors);
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "id", result.Errors);
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "version", result.Errors);

                if (result.Errors.Count > 0)
                {
                    // the edit request was invalid so don't waste any more cycles on this request 
                    return result;
                }

                result.EditMetadata = metadata;

                JToken catalogEntryAddress;
                if (metadata.TryGetValue("catalogEntry", out catalogEntryAddress))
                {
                    JObject catalogEntry = await CatalogHelpers.LoadFromCatalog(catalogEntryAddress.ToString(), Configuration.StoragePrimary, Configuration.StorageContainerCatalog, Configuration.CatalogBaseAddress);

                    if (catalogEntry != null)
                    {
                        result.CatalogEntry = catalogEntry;
                        result.PackageIdentity = PackageIdentity.FromCatalogEntry(catalogEntry);

                        JToken isListed;
                        if (metadata.TryGetValue("listed", out isListed))
                        {
                            if (isListed.Type != JTokenType.Boolean)
                            {
                                result.Errors.Add("listed must be a boolean value");
                            }
                            else
                            {
                                result.Listed = isListed.ToObject<bool>();
                            }
                        }
                        else
                        {
                            result.Listed = catalogEntry["listed"].ToObject<bool>();
                        }

                        ValidateEdit(result);
                    }
                    else
                    {
                        result.Errors.Add("unable to load catalogEntry");
                    }
                }
                else
                {
                    result.Errors.Add("corresponding catalogEntry must be specified");
                }
            }
            else
            {
                result.Errors.Add("unable to read content as JSON");
            }

            return result;
        }
 protected virtual void ValidateEdit(EditValidationResult result)
 {
 }
        public async Task Edit(IOwinContext context)
        {
            Trace.TraceInformation("PublishImpl.Edit");

            if (!_registrationOwnership.IsAuthenticated)
            {
                await ServiceHelpers.WriteErrorResponse(context, "user does not have access to the service", HttpStatusCode.Forbidden);
                return;
            }

            if (!await _registrationOwnership.HasTenantEnabled())
            {
                await ServiceHelpers.WriteErrorResponse(context, "package publication has not been enabled in this tenant", HttpStatusCode.Forbidden);
                return;
            }

            PublicationVisibility publicationVisibility;
            if (!PublicationVisibility.TryCreate(context, out publicationVisibility))
            {
                await ServiceHelpers.WriteErrorResponse(context, "specify either organization OR subscription NOT BOTH", HttpStatusCode.BadRequest);
                return;
            }

            Stream metadataStream = context.Request.Body;

            //  validation

            EditValidationResult validationResult = await ValidateEdit(metadataStream);

            if (validationResult.HasErrors)
            {
                await ServiceHelpers.WriteErrorResponse(context, validationResult.Errors, HttpStatusCode.BadRequest);
                return;
            }

            //  registration authorization

            IList<string> authorizationErrors = await OwnershipHelpers.CheckRegistrationAuthorizationForEdit(_registrationOwnership, validationResult.PackageIdentity);

            if (authorizationErrors.Count > 0)
            {
                await ServiceHelpers.WriteErrorResponse(context, authorizationErrors, HttpStatusCode.Forbidden);
                return;
            }

            Trace.TraceInformation("EDIT Processing package {0}/{1}/{2} listed: {3}", validationResult.PackageIdentity.Namespace, validationResult.PackageIdentity.Id, validationResult.PackageIdentity.Version, validationResult.Listed);

            //  process the edit

            IDictionary<string, JObject> metadata = new Dictionary<string, JObject>();

            //  (1) generate any new or replacement artifacts based on the current catalogEntry and the editMetadata

            IDictionary<string, PackageArtifact> artifacts = await GenerateNewArtifactsFromEdit(metadata, validationResult.CatalogEntry, validationResult.EditMetadata, Configuration.StoragePrimary);

            Trace.TraceInformation("GenerateNewArtifactsFromEdit");
            
            //  (2) save the new package

            await Artifacts.Save(metadata, artifacts, Configuration.StoragePrimary, Configuration.StorageContainerArtifacts);

            InferArtifactTypes(metadata);

            Trace.TraceInformation("Save");

            //  (3) promote the relevant peices of metadata so they later can appear on the catalog page 

            await GenerateNuspec(metadata);

            Trace.TraceInformation("GenerateNuspec");

            //  (4) gather all the publication details

            PublicationDetails publicationDetails = await OwnershipHelpers.CreatePublicationDetails(_registrationOwnership, publicationVisibility);

            Trace.TraceInformation("CreatePublicationDetails");

            //  (5) add the new item to the catalog

            Uri catalogAddress = await AddToCatalog(metadata["nuspec"], GetItemType(), publicationDetails, validationResult.Listed);

            Trace.TraceInformation("AddToCatalog");

            //  (6) update the registration ownership record

            await UpdateRegistrationOwnership(validationResult.PackageIdentity);

            Trace.TraceInformation("UpdateRegistrationOwnership");

            //  (7) create response

            JToken response = new JObject
            { 
                { "download", metadata["nuspec"]["packageContent"] },
                { "catalog", catalogAddress.ToString() }
            };

            await ServiceHelpers.WriteResponse(context, response, HttpStatusCode.OK);
        }
        async Task<EditValidationResult> ValidateEdit(Stream metadataStream, CancellationToken cancellationToken)
        {
            EditValidationResult result = new EditValidationResult();

            JObject metadata = await ServiceHelpers.ReadJObject(metadataStream);
            if (metadata != null)
            {
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "namespace", result.Errors);
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "id", result.Errors);
                ValidationHelpers.CheckDisallowedEditProperty(metadata, "version", result.Errors);

                if (result.Errors.Count > 0)
                {
                    // the edit request was invalid so don't waste any more cycles on this request 
                    return result;
                }

                result.EditMetadata = metadata;

                JToken catalogEntryAddress;
                if (metadata.TryGetValue("catalogEntry", out catalogEntryAddress))
                {
                    JObject catalogEntry = await CatalogHelpers.LoadFromCatalog(catalogEntryAddress.ToString(), Configuration.StoragePrimary, Configuration.StorageContainerCatalog, Configuration.CatalogBaseAddress, cancellationToken);

                    if (catalogEntry != null)
                    {
                        result.CatalogEntry = catalogEntry;
                        result.PackageIdentity = PackageIdentity.FromCatalogEntry(catalogEntry);

                        JToken isListed;
                        if (metadata.TryGetValue("listed", out isListed))
                        {
                            if (isListed.Type != JTokenType.Boolean)
                            {
                                result.Errors.Add("listed must be a boolean value");
                            }
                            else
                            {
                                result.Listed = isListed.ToObject<bool>();
                            }
                        }
                        else
                        {
                            result.Listed = catalogEntry["listed"].ToObject<bool>();
                        }

                        ValidateEdit(result);
                    }
                    else
                    {
                        result.Errors.Add("unable to load catalogEntry");
                    }
                }
                else
                {
                    result.Errors.Add("corresponding catalogEntry must be specified");
                }
            }
            else
            {
                result.Errors.Add("unable to read content as JSON");
            }

            return result;
        }