Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Kostiantyn Chomakov 10 posts 78 karma points
    Jan 06, 2017 @ 00:04
    Kostiantyn Chomakov
    0

    Implementing ISyncHandler for Members

    Hi!

    So, after seeing this topic: https://our.umbraco.org/projects/developer-tools/usync/usync/74139-are-there-any-plans-to-exportsync-members

    as it was proposed in there i am trying to implement new handler for export and import of members.

    As an example i've taken built-in MemberTypeHandler. As far as i can see my job here is to develop proper serializer for this umbraco type and here where i stuck.

    1) I am deriving my serializer from ISyncSerializerTwoPass, ISyncChangeDetail, ISyncSerializer. To serialize method i am passing Member received by memberservice but it lacks properties and groups. How can i receive this information?

    2) As far as i understand i must "assemble" complete object before it goes further in pipeline in Deserialize method. But how can i set MemberGroups for it inside serializer so that it will be properly added in system?

    Than you in advance for attention and help!

  • Kevin Jump 991 posts 5547 karma points mvp c-trib
    Jan 06, 2017 @ 15:35
    Kevin Jump
    0

    Hi

    Glad your having a go at this, and i am happy to answer any quesitons it might throw up :)

    Looking at the way the membership service is structured it might make sense to also have a MemberGroup Handler/Service that creates the groups and puts the members in them.

    like a member handler This would need to attached to the membersave, etc to make sure it captured the group info, but it would probably result in cleaner code as it will match the services better.

  • Kostiantyn Chomakov 10 posts 78 karma points
    Jan 06, 2017 @ 16:40
    Kostiantyn Chomakov
    0

    Sorry didnt quite catch you.

    Lets say i am looking on Jumoo.uSync.Core.Serializers.MemberTypeSerializer as i can see there new object is created from xml to go further on pipeline.

    I am creating such serializer for members. How can set role to member object during deserialization which doesn't exist in database ?

  • Kevin Jump 991 posts 5547 karma points mvp c-trib
    Jan 06, 2017 @ 16:52
    Kevin Jump
    0

    Hi,

    yeah you will need to create the roles - either during the deserialization of the member - if the role doesn't exist create it using the MemberGroup Service https://our.umbraco.org/documentation/Reference/Management/Services/MemberGroupService

    or decouple the roles from the members have a Member Group Handler that runs after the member handler (so the members will be in the db) to add/remove members from groups.

  • Kostiantyn Chomakov 10 posts 78 karma points
    Jan 30, 2017 @ 14:33
    Kostiantyn Chomakov
    0

    Hi Kevin. I m sorry it seems i didn't get your point. I was looking though code of existing handlers and serializers and tried to create something equal for members.

    Please take a look on classes below especially at serializer class. Do i do it correct? If yes then how can how can i accomplish next aims:

    1) //TODO: How to change MemberType if current one is incorrect? 2) //TODO: How to set/change membergroups for existing member and for new which is not being persisted in serializer!?

  • Kostiantyn Chomakov 10 posts 78 karma points
    Jan 30, 2017 @ 14:34
    Kostiantyn Chomakov
    0
     public class MemberSerializer : SyncSerializerBase<IMember>, ISyncSerializerTwoPass<IMember>, ISyncChangeDetail
    {
        private readonly IMemberService _memberService;
    
        public MemberSerializer() : base(SerializationEx.Member)
        {
            _memberService = ApplicationContext.Current.Services.MemberService;
        }
    
        public override String SerializerType => SerializationEx.Member;
        public override Int32 Priority { get; } = PriorityEx.Member;
    
        public SyncAttempt<IMember> Deserialize(XElement node, bool forceUpdate, bool onePass)
        {
            var syncAttempt = DeSerialize(node, false);
            if (!onePass || !syncAttempt.Success || syncAttempt.Item == null)
                return syncAttempt;
            return DesearlizeSecondPass(syncAttempt.Item, node);
        }
    
        public SyncAttempt<IMember> DesearlizeSecondPass(IMember item, XElement node)
        {
            return SyncAttempt<IMember>.Succeed(node.NameFromNode(), ChangeType.NoChange);
        }
    
        public override SyncAttempt<XElement> SerializeCore(IMember item)
        {
            LogHelper.Debug<MemberSerializer>($"Member {item.Name} serialization has started.");
            var element = new XElement("Member", 
                SerializeInfo(item),
                SerializeRoles(item),
                SerializeProperties(item));
    
            LogHelper.Debug<MemberSerializer>($"Member {item.Name} serialization has completed.");
            return SyncAttempt<XElement>.Succeed(item.Name, element, typeof(IMember), ChangeType.Export);
        }
    
        private XElement SerializeInfo(IMember item)
        {
            return new XElement("Info", 
                new XElement(uSyncConstants.Key, item.Key),
                new XElement("Type", item.GetType().GetTypeAndAssemblyName()),
                new XElement("Username", item.Username),
                new XElement("Name", item.Name),
                new XElement("Email", item.Email),
                new XElement("Comments", item.Comments),
                new XElement("Updated", item.UpdateDate.ToString("yyyy-MM-ddTHH:mm:ss.fffffff'Z'")),
                new XElement(uSyncConstants.ContentTypeAlias, item.ContentTypeAlias));
        }
    
        private XElement SerializeRoles(IMember item)
        {
            var rolesElement = new XElement("Roles");
            var roles = System.Web.Security.Roles.GetRolesForUser(item.Username);
            foreach (var role in roles)
            {
                rolesElement.Add(new XElement("Role", role));
            }
            return rolesElement;
        }
    
        private XElement SerializeProperties(IMember item)
        {
            var propertiesElement = new XElement("Properties");
            foreach (var property in item.Properties.Where(p => p != null))
            {
                XElement propertyElement;
                try
                {
                    propertyElement = property.ToXml();
                }
                catch
                {
                    propertyElement = new XElement(property.Alias, property.Value);
                }
                var exportIds = GetExportIds(property.PropertyType, propertyElement);
                var xelement3 = XElement.Parse(string.Format("<{0}>{1}</{0}>", propertyElement.Name, exportIds), LoadOptions.PreserveWhitespace);
                propertiesElement.Add(xelement3);
            }
            return propertiesElement;
        }
    
        public override SyncAttempt<IMember> DeserializeCore(XElement node)
        {
            LogHelper.Debug<MemberSerializer>($"Member deserialization has started.");
    
            var keyElement = node.Element(uSyncConstants.Key);
            if (keyElement == null)
                throw new ArgumentException($"Serialized node doesnt contain \"{uSyncConstants.Key}\" element.");
            var memberTypeElement = node.Element(uSyncConstants.ContentTypeAlias);
            if (memberTypeElement == null)
                throw new ArgumentException($"Serialized node doesnt contain \"{uSyncConstants.ContentTypeAlias}\" element.");
    
            IMember member = null;
                var key = node.Element(uSyncConstants.Key).ValueOrDefault(Guid.Empty);
            if (key != Guid.Empty)
            {
                member = _memberService.GetByKey(key);
                if (member != null)
                {
                    //TODO: How to change MemberType if current one is incorrect?
                    member.Name = node.Element(uSyncConstants.Name).ValueOrDefault(member.Name);
                    member.Username = node.Element(uSyncConstants.Member.Username).ValueOrDefault(member.Username);
                    member.Email = node.Element(uSyncConstants.Member.Email).ValueOrDefault(member.Email);
                }
            }
            if (member == null)
            {
                member = _memberService.CreateMember(
                    node.Element(uSyncConstants.Member.Username).ValueOrDefault(String.Empty),
                    node.Element(uSyncConstants.Name).ValueOrDefault(String.Empty),
                    node.Element(uSyncConstants.Member.Email).ValueOrDefault(String.Empty),
                    memberTypeElement.Value);
            }
    
            var propertiesElement = node.Element("Properties");
            if (propertiesElement != null)
            {
                foreach (var property in propertiesElement.Elements())
                {
                    var propertyTypeAlias = property.Name.LocalName;
                    if (member.HasProperty(propertyTypeAlias))
                    {
                        var newValue = GetImportIds(member.Properties[propertyTypeAlias].PropertyType, GetImportXml(property));
                        try
                        {
                            member.SetValue(propertyTypeAlias, newValue);
                        }
                        catch (InvalidOperationException ex)
                        {
                            LogHelper.Warn<SyncSerializerBase<IMember>>(
                                "Setting a value didn't work. Tried to set value '{0}' to the property '{1}' on '{2}'. Exception: {3}", 
                                () => newValue, () => propertyTypeAlias, () => member.Name, () => ex.Message);
                        }
                    }
                }
            }
    
    
            //TODO: How to set membergroup?
    
                LogHelper.Debug<MemberSerializer>($"Member {member.Name} deserialization has completed.");
            return SyncAttempt<IMember>.Succeed(member.Name, member, ChangeType.Import, String.Empty);
        }
    
        public override bool IsUpdate(XElement node)
        {
            //var key = node.Attribute((XName)"guid").ValueOrDefault(Guid.Empty);
            //if (key == Guid.Empty)
            //    return true;
            //var byId = _memberService.GetByKey(key);
            //return byId == null || (node.Attribute((XName)"updated").ValueOrDefault(DateTime.Now).ToUniversalTime() - byId.UpdateDate.ToUniversalTime()).TotalSeconds > 1.0;
            var syncHash1 = node.GetSyncHash();
            if (string.IsNullOrEmpty(syncHash1))
                return true;
            var xelement = node.Element("Info")?.Element(uSyncConstants.Key);
            if (xelement == null)
                return true;
            var member = _memberService.GetByKey(Guid.Parse(xelement.Value));
            if (member == null)
                return true;
            var syncAttempt = Serialize(member);
            if (!syncAttempt.Success)
                return true;
            var syncHash2 = syncAttempt.Item.GetSyncHash();
            return !syncHash1.Equals(syncHash2);
        }
    
        public IEnumerable<uSyncChange> GetChanges(XElement node)
        {
            if (string.IsNullOrEmpty(node.GetSyncHash()))
                return null;
            var xelement = node.Element("Info")?.Element(uSyncConstants.Key);
            if (xelement == null)
                return null;
            var member = _memberService.GetByKey(Guid.Parse(xelement.Value));
            if (member == null)
                return uSyncChangeTracker.NewItem(xelement.Value);
            var syncAttempt = this.Serialize(member);
            return syncAttempt.Success 
                ? uSyncChangeTracker.GetChanges(node, syncAttempt.Item, "")
                : uSyncChangeTracker.ChangeError(xelement.Value);
        }
    }
    
  • Kostiantyn Chomakov 10 posts 78 karma points
    Jan 30, 2017 @ 14:35
    Kostiantyn Chomakov
    0
    public class MemberHandler : uSyncBaseHandler<IMember>, ISyncHandler
    {
        public int Priority => PriorityEx.Member;
        public string Name => "uSync: MemberHandler";
        public string SyncFolder => "Member";
    
        private readonly IMemberService _memberService;
        private readonly ISyncSerializerTwoPass<IMember> _serializer;
    
        public MemberHandler()
        {
            _memberService = ApplicationContext.Current.Services.MemberService;
            _serializer = new MemberSerializer();
        }
    
        public IEnumerable<uSyncAction> ExportAll(String folder)
        {
            LogHelper.Info<MemberHandler>("Exporting Members");
    
            var actions = new List<uSyncAction>();
    
            foreach (var member in _memberService.GetAllMembers())
            {
                var memberPath = Path.Combine(String.Empty, member.Name.ToSafeFileName());
                actions.Add(ExportMember(member, memberPath, folder));
            }
    
            return actions;
        }
    
        public override SyncAttempt<IMember> Import(string filePath, bool force = false)
        {
            LogHelper.Debug<MemberHandler>("Importing Member : {0}", () => filePath);
            if (!System.IO.File.Exists(filePath))
                throw new FileNotFoundException(filePath);
    
            var node = XElement.Load(filePath);
            return _serializer.Deserialize(node, force, false);
        }
    
        public override uSyncAction ReportItem(string file)
        {
            var node = XElement.Load(file);
            var uSyncAction = uSyncActionHelper<IMember>.ReportAction(_serializer.IsUpdate(node), node.NameFromNode());
            if (uSyncAction.Change > ChangeType.NoChange)
                uSyncAction.Details = ((ISyncChangeDetail)_serializer).GetChanges(node);
            return uSyncAction;
        }
    
        public void RegisterEvents()
        {
            MemberService.Saved += MemberServiceSaved;
            MemberService.Deleted += MemberService_Deleted;
        }
    
        public override void ImportSecondPass(String file, IMember item)
        {
            if (!System.IO.File.Exists(file))
                throw new FileNotFoundException();
            var node = XElement.Load(file);
            _serializer.DesearlizeSecondPass(item, node);
        }
    
        private void MemberServiceSaved(IMemberService sender, SaveEventArgs<IMember> e)
        {
            if (uSyncEvents.Paused)
                return;
    
            SaveItems(sender, e.SavedEntities);   
        }
    
        private void MemberService_Deleted(IMemberService sender, DeleteEventArgs<IMember> e)
        {
            if (uSyncEvents.Paused)
                return;
    
            foreach (var deletedEntity in e.DeletedEntities)
            {
                LogHelper.Info<MediaTypeHandler>("Delete: Remove usync files for {0}", () => deletedEntity.Name);
                uSyncIOHelper.ArchiveRelativeFile(SyncFolder, GetMemberPath(deletedEntity), uSyncConstants.FileName);
                uSyncBackOfficeContext.Instance.Tracker.AddAction(SyncActionType.Delete, deletedEntity.Key, deletedEntity.Name, typeof(IMember));
            }
        }
    
        private void SaveItems(IMemberService sender, IEnumerable<IMember> savedMembers)
        {
            foreach (var savedMember in savedMembers)
            {
                LogHelper.Info<MemberHandler>("Save: Saving uSync files for : {0}", () => savedMember.Name);
                var member = _memberService.GetById(savedMember.Id);
                var path = GetMemberPath(member);
                var attempt = ExportMember(member, path, uSyncBackOfficeContext.Instance.Configuration.Settings.Folder);
                if (attempt.Success)
                {
                    NameChecker.ManageOrphanFiles(SyncFolder, member.Key, attempt.FileName);
                }
            }
        }
    
        private string GetMemberPath(IMember member)
        {
            var path = member.Name.ToSafeFileName();
            if (member.ParentId != -1)
            {
                path = $"{GetMemberPath(_memberService.GetById(member.ParentId))}\\{path}";
            }
    
            return path;
        }
    
        private uSyncAction ExportMember(IMember member, String path, String folder)
        {
            if (member == null)
                return uSyncAction.Fail(Path.GetFileName(path), typeof(IMember), "Member not set");
    
            try
            {
                var attempt = _serializer.Serialize(member);
    
                var filename = string.Empty;
                if (attempt.Success)
                {
                    filename = uSyncIOHelper.SavePath(folder, SyncFolder, path, uSyncConstants.FileName);
                    uSyncIOHelper.SaveNode(attempt.Item, filename);
                }
    
                return uSyncActionHelper<XElement>.SetAction(attempt, filename);
            }
            catch (Exception ex)
            {
                LogHelper.Warn<MemberHandler>("Error saving Member: {0}", () => ex.ToDetailedString());
                return uSyncAction.Fail(member.Name, typeof(IMember), ChangeType.Export, ex);
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft