Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

umbraco deploy & vorto-ising existing properties #105

Closed
AussieInSeattle opened this issue Jun 4, 2018 · 4 comments
Closed

umbraco deploy & vorto-ising existing properties #105

AussieInSeattle opened this issue Jun 4, 2018 · 4 comments
Labels

Comments

@AussieInSeattle
Copy link

AussieInSeattle commented Jun 4, 2018

I'm having an issue with Vorto on Umbraco Cloud when pushing an existing node from local dev to dev/staging on umbraco cloud or from dev/staging cloud to live cloud – the doc type/node had 1 property changed from being non-vorto to vorto without a change in property name – I'm assuming the issue is in the code that reads the value in from Live for the “something has changed” comparison and it is expecting that value to be a json string (vorto string) and its not as it was previously not a vorto data type and just a normal textstring data type.

Error from Umbraco Cloud/Deploy

It was not possible to transfer changes
An error occurred while transferring the selected changes, so the transfer could not finish.

If you are an editor then please contact your developers or admins with the technical details listed below for help in resolving the issue.

Troubleshooting deploy errors

Read developer documentation on troubleshooting schema problems

Details:

Here is some technical information that might help shed some light on whats happened:

An error occurred

Error: Server was unable to process request. ---> Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Umbraco.Courier.Contrib.Resolvers.PropertyDataResolvers.VortoPropertyDataResolver+VortoPropertyData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path '', line 1, position 1.

Details: System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Umbraco.Courier.Contrib.Resolvers.PropertyDataResolvers.VortoPropertyDataResolver+VortoPropertyData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path '', line 1, position 1.
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.EndInvoke(IAsyncResult asyncResult)
at Umbraco.Courier.RepositoryProviders.WebServiceProvider.RepositoryWebservice.EndGetHashes(IAsyncResult asyncResult)
at Umbraco.Courier.RepositoryProviders.CourierWebserviceRepositoryProvider.GetHashes(ItemIdentifier[] itemIds)
at Umbraco.Courier.Core.Packaging.RevisionPackaging.GetTargetHashes(IPackagingTarget2 target, IEnumerable`1 ids)
at Umbraco.Courier.Core.Packaging.RevisionPackaging.PackageBatch()
at Umbraco.Courier.Core.Packaging.RevisionPackaging.Package()
at Umbraco.Courier.Core.Tasks.PackagingTask.Run()
at Umbraco.Courier.Core.BackgroundTaskRunner`1.ConsumeTaskInternal(T task)
@leekelleher
Copy link
Contributor

Hey @AussieInSeattle, thanks for reporting this, unfortunately it's outside the control of Vorto itself ... it's more an issue with Umbraco Cloud and the Courier Contrib library. But I'll try to help you pin point the underlying issue.

Firstly, do you know if your Cloud project is using Courier or Deploy? If it's Deploy, then the Courier Contrib library shouldn't be there. (There's a separate Deploy Contrib library - but that should ship with all Cloud projects anyway.)

If you are on Courier, then did the schema change (for changing the property data-type to Vorto) get successfully deployed to the target environment? If not, then best to take that specific point with Umbraco Cloud support.

If the schema change did go up - which I suspect it did (but I'm covering all bases here) - then Courier is doing as you say, looking up the old value (of the old data-type - let's say a textstring), and assuming that it's a Vorto value, so tries to use the Vorto Courier data-resolver ... and then it blows up (because it's not JSON).

The only workaround that I could see (without code fixes) is on the target environment, to manually republish all the content nodes that have that updated property. As that should clear out the values. Then you should be able to do a content-transfer from your source environment to the target environment.

(gawd, I know too much about Courier's quirks & workarounds) 🤕

If you suspect this is a wider issue with Courier and the contrib data-resolvers, then try raising an issue on the Courier Contrib repo.

Good luck!

@AussieInSeattle
Copy link
Author

AussieInSeattle commented Jun 5, 2018

Hey @leekelleher - appreciate the detailed thought/response - here I was thinking you were just an upcoming yet talented puppeteer.

When I login to umbraco.io and look at the cloud project it says:
Umbraco 7.5.14, Forms 4.4.7, Courier 3.1.7
So I assume we are using Courier? If that is not the right way to check, let me know.

I managed to get everything deployed (this was at CG18) so no rush on this issue - detailed steps below on the workaround.

I first tried your suggestion of just deploying the change in data-type via git to the Dev Cloud environment which updated the data type to Vorto, and then doing a save and publish on Dev Cloud which I assume would have changed the existing string value from something like "string" to "{"values":{"en-us":""}}". While not ideal (I lose existing data and some other vorto changes were nested content so hard to re-enter) this didnt actually work and the Deployment from local dev to Cloud Dev still failed with the same error - I would have expected that to work but moved onto a second solution detailed below.

As an a-side, I suspect the underlying issue is with this line as it does not fail gracefully when you dont pass in a json string:
https://github.com/umbraco/Umbraco.Courier.Contrib/blob/dev/src/Umbraco.Courier.Contrib.Resolvers/PropertyDataResolvers/VortoPropertyDataResolver.cs#L61
? If you agree, I'll raise an issue over there.

Since the above did not work for me, I wrote a quick and dirty API controller that I could pass a content id and propertyname into and it would pull the existing property value (a string for example) and then create a vorto value for it (en-us) and save the content. The deploy then worked and I also got to keep my "existing" data as default in en-us. That got me thinking about making the code behind that API controller a Vorto "feature" that is controlled by a pre-value checkbox that when checked will auto-create a vorto value on the first save+publish if the vorto value already existed as a different property type - it would still trigger off the save+publish button, similar to what we expected to work in the first attempt above, except it would shove the existing/current value into the default/first language so you dont lose anything when you're "vorto-izing" an existing site?

Here's the code I used in the API Controller:

    public HttpResponseMessage SetProperty(string nodeId, string propertyName, string reset)
    {
        StringBuilder sb = new StringBuilder();

        //var content = Umbraco.TypedContent(nodeId);
        var content = Services.ContentService.GetById(int.Parse(nodeId));
        if (content != null)
        {
            var property = content.Properties.FirstOrDefault(x => x.Alias == propertyName);
            if (property == null)
                sb.AppendFormat("<strong>{0}<strong><br/>", "Property on Node not found");
            else
            {
                var currentValue = property.Value.ToString();
                if (currentValue.Contains("dtdGuid") && currentValue.StartsWith("{\"values\":{") && string.IsNullOrEmpty(reset))
                    sb.AppendFormat("<strong>{0}<strong><br/>", "Property is already a Vorto set property");
                else
                {
                    //get the guid
                    var dtdId = property.PropertyType.DataTypeDefinitionId;
                    var dtd = Services.DataTypeService.GetDataTypeDefinitionById(dtdId);

                    var vortoValue = new VortoValue();
                    vortoValue.DtdGuid = dtd.Key;
                    vortoValue.Values = new Dictionary<string, object>();
                    // Assign the old property value to your default language
                    if (string.IsNullOrEmpty(reset))
                        vortoValue.Values.Add("en-US", property.Value);
                    else
                        vortoValue.Values.Add("en-US", null);
                    // Set the value as the new vorto wrapped value and save.
                    //var contentDB = Services.ContentService.GetById(int.Parse(nodeId));
                    //contentDB.Properties.FirstOrDefault()
                    content.SetValue(propertyName, JsonConvert.SerializeObject(vortoValue));
                    Services.ContentService.SaveAndPublishWithStatus(content);
                    sb.AppendFormat("<strong>{0}<strong><br/>", "Node Saved");
                }
            }
        }
        else
            sb.AppendFormat("<strong>{0}<strong><br/>", "Node not found");

        var resp = new HttpResponseMessage();
        resp.StatusCode = HttpStatusCode.OK;
        resp.Content = new StringContent(sb.ToString());
        resp.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
        return resp;
    }

@leekelleher
Copy link
Contributor

@AussieInSeattle - oh yes, while I'd love my sock puppet career to take off, my hands are tied in Umbracoland. 😆

Thanks for the update and code snippet. It's definitely Courier.

With all this I see two distinct parts...

  1. Should Vorto attempt to keep the existing property-value? and if so, how? (I have suggestions for @mattbrailsford below)
  2. Should Courier (and/or Deploy) handle this gracefully, (rather than an abrupt exception)?

To get Courier contrib concern out the way, the VortoPropertyDataResolver could handle this more gracefully. Personally I don't think it should be trying to "vorto-ize" the value, but it could be handled better. So yes, best to raise an issue about that on the Courier contrib issue tracker.


The idea of an existing site being "vorto-ized" is interesting. (To pull @mattbrailsford into the discussion here) ... in one of our other property-editors, Property List, I wanted it to be hotswappable with the "Repeatable Textstring" editor. So I added code to check if the value was JSON or not and made an assumption that it was a textstring.

https://github.com/umco/umbraco-property-list/blob/develop/src/Our.Umbraco.PropertyList/PropertyEditors/PropertyListPropertyValueEditor.cs#L45-L52

@mattbrailsford - It could be possible to do the same in Vorto's ConvertDbToEditor method?
We might be able to find out from the propertyType to which data-type is being referenced, then wrap the existing (non-JSON) value in a VortoValue?

@mattbrailsford mattbrailsford changed the title umbraco deploy issue with vorto umbraco deploy & vorto-ising existing properties Aug 17, 2018
@leekelleher
Copy link
Contributor

Just to note, the enhancement in 32d2f78 doesn't resolve the Courier deployment issue. That would still need to be handled in the Courier Contrib project/repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants