Exemple #1
0
        public void ConnectToDeki(string dreamAPI, string dekiUserName, string dekiUserPassword)
        {
            this._dreamAPI = dreamAPI;
            this._dekiPlug = Plug.New(_dreamAPI).WithCredentials(dekiUserName, dekiUserPassword);

            DreamMessage authResponse = _dekiPlug.At("users", "authenticate").GetAsync().Wait();

            if (!authResponse.IsSuccessful)
            {
                Log.FatalFormat("Could not connect to MT API '{0}' username: '******' password: '******' Error:", _dekiPlug.ToString(), dekiUserName, dekiUserPassword, authResponse.ToString());
                throw new DreamAbortException(authResponse);
            }

            //Check that user have admin rights
            DreamMessage userResponse = _dekiPlug.At("users", "=" + Utils.DoubleUrlEncode(dekiUserName)).Get();
            XDoc         resDoc       = userResponse.AsDocument();
            string       roleName     = resDoc["permissions.user/role"].AsText;

            if ((roleName == null) || (roleName.ToLower() != "admin"))
            {
                WriteLineToConsole("User " + dekiUserName + " should have Admin role in Deki.");
                return;
            }

            _connectedToDeki = true;
        }
        public void Bug_MT8962_PostPageContentsWithFile()
        {
            Plug adminPlug = Utils.BuildPlugForAdmin();

            // Create random contributor
            string       username = null;
            string       userid   = null;
            DreamMessage msg      = UserUtils.CreateRandomUser(adminPlug, "Contributor", "password", out userid, out username);

            // Login as user
            Plug userPlug = Utils.BuildPlugForUser(username);

            // Create a page
            string page_id;
            string page_path;

            msg = PageUtils.CreateRandomPage(userPlug, out page_id, out page_path);

            // Create a file
            string fileName = FileUtils.CreateRamdomFile(null);

            msg      = DreamMessage.FromFile(fileName);
            fileName = "foo.jpg";

            // Upload file to page
            msg = userPlug.At("pages", page_id, "files", "=" + fileName).Put(msg);
            Assert.AreEqual(DreamStatus.Ok, msg.Status, "PUT request failed");

            // update the page
            XDoc pageContents = new XDoc("content");

            pageContents.Attr("type", "application/x.deki-text");
            pageContents.Attr("unsafe", "false");
            pageContents.Start("body");
            pageContents.Start("img");
            pageContents.Attr("class", "internal default");
            pageContents.Attr("src.path", "//");
            pageContents.Attr("src.filename", fileName);
            pageContents.End(); //img
            pageContents.End(); //body

            msg = userPlug.At("pages", page_id, "contents")
                  .With("edittime", "now")
                  .With("redirects", 0)
                  .With("reltopath", page_path)
                  .Post(pageContents);
            Assert.AreEqual(DreamStatus.Ok, msg.Status, "page creation failed!");

            msg = userPlug.At("pages", page_id, "contents")
                  .With("mode", "view")
                  .Get();

            string contents  = msg.AsDocument()["/content/body"].Contents;
            XDoc   imgDoc    = XDocFactory.From(contents, MimeType.XML);
            XUri   imgSrcUri = XUri.TryParse(imgDoc["@src"].AsText);

            Assert.IsNotNull(imgSrcUri, "img src uri is invalid!");
        }
Exemple #3
0
        public void CheckBannedUsersPerms()
        {
            //Assumptions:
            //
            //Actions:
            // Create user1 as contributor
            // Ban user1
            // create public page p1
            // Call POST: pages/{p1}/allowed with user1
            //Expected result:
            // user1 should not have access to p1

            Plug p = Utils.BuildPlugForAdmin();

            string       userId   = null;
            string       userName = null;
            DreamMessage msg      = UserUtils.CreateRandomContributor(p, out userId, out userName);

            // confirm user has perms
            msg = p.At("users", userId).Get();
            Assert.IsTrue((msg.AsDocument()["permissions.effective/operations"].AsText ?? string.Empty).ContainsInvariantIgnoreCase("UPDATE"), "user doesnt have expected perms");

            // ban the user
            XDoc ban = new XDoc("bans")
                       .Elem("description", Utils.GetSmallRandomText())
                       .Elem("date.expires", DateTime.Now.AddDays(10))
                       .Start("permissions.revoked")
                       .Elem("operations", banRevokemask)
                       .End()
                       .Start("ban.users")
                       .Start("user").Attr("id", userId).End()
                       .End();

            msg = p.At("site", "bans").Post(ban);
            Assert.AreEqual(DreamStatus.Ok, msg.Status);

            // confirm user has perms
            msg = p.At("users", userId).Get();
            Assert.IsFalse((msg.AsDocument()["permissions.effective/operations"].AsText ?? string.Empty).ContainsInvariantIgnoreCase("UPDATE"), "user doesnt have expected perms");
        }
        private int CreateDekiPage(Plug p, string pagePath, string pageTitle, DateTime?modified, string content,
                                   out string dekiPageUrl)
        {
            Log.DebugFormat("Creating page: '{0}' Content? {1}", XUri.DoubleDecode(pagePath), !string.IsNullOrEmpty(content));

            Plug pagePlug = p.At("pages", "=" + pagePath, "contents");

            pagePlug = pagePlug.With("abort", "never");
            modified = modified ?? DateTime.Now;
            string editTime = Utils.FormatPageDate(modified.Value.ToUniversalTime());

            pagePlug = pagePlug.With("edittime", editTime);
            pagePlug = pagePlug.With("comment", "Created at " + modified.Value.ToShortDateString() + " " + modified.Value.ToShortTimeString());
            if (pageTitle != null)
            {
                pagePlug = pagePlug.With("title", pageTitle);
            }
            DreamMessage msg = DreamMessage.Ok(MimeType.TEXT_UTF8, content);

            DreamMessage res = pagePlug.PostAsync(msg).Wait();

            if (res.Status != DreamStatus.Ok)
            {
                WriteLineToConsole("Error converting page \"" + XUri.DoubleDecode(pagePath) + "\"");
                WriteLineToLog("Edit time: " + editTime);
                WriteLineToLog("Page title: " + pageTitle);
                WriteErrorResponse(res);
                WriteErrorRequest(msg);
            }
            else
            {
                XDoc createdPage = res.AsDocument();
                int  pageId      = createdPage["page/@id"].AsInt.Value;

                //dekiPageUrl = createdPage["page/path"].AsText;

                //Using the uri.ui instead of path to not worry about encodings for links
                //But this makes the values (mt urls) in the link mapping table unsuitable for page paths
                //(such as those used in dekiscript for macros). Those need to be converted to paths
                // via Utils.ConvertPageUriToPath
                dekiPageUrl = createdPage["page/uri.ui"].AsText;

                return(pageId);
            }
            dekiPageUrl = null;
            return(-1);
        }
        public void GetPageCreatorInfo()
        {
            Plug p = Utils.BuildPlugForAdmin();

            string content = "This is test content";

            string       id   = null;
            string       path = null;
            DreamMessage msg  = PageUtils.SavePage(p, string.Empty,
                                                   PageUtils.GenerateUniquePageName(), content, out id, out path);

            msg = p.At("users", "current").Get();
            var pageCreatorId = msg.AsDocument()["@id"].AsText;

            PageUtils.SavePage(p, path, "New content");
            var pageDoc = p.At("pages", id).Get().ToDocument();

            Assert.AreEqual(pageCreatorId, pageDoc["user.createdby/@id"].AsText);
            Assert.IsTrue((pageDoc["date.created"].AsDate ?? DateTime.MinValue) > DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(5)), "create date missing.");
            PageUtils.DeletePageByID(p, id, true);
        }
Exemple #6
0
        private int CreateDekiPageHistory(Plug p, string pagePath, string pageTitle, DateTime?modified, string content,
                                          out string dekiPageUrl)
        {
            Log.DebugFormat("Creating page history: '{0}' Content? {1}", XUri.DoubleDecode(pagePath), !string.IsNullOrEmpty(content));

            Plug pagePlug = p.At("pages", "=" + pagePath, "revision");

            pagePlug = pagePlug.With("abort", "never");
            modified = modified ?? DateTime.Now;
            string editTime = Utils.FormatPageDate(modified.Value.ToUniversalTime());

            pagePlug = pagePlug.With("edittime", editTime);
            if (pageTitle != null)
            {
                pagePlug = pagePlug.With("title", pageTitle);
            }
            DreamMessage msg = DreamMessage.Ok(MimeType.TEXT_UTF8, content);

            DreamMessage res = pagePlug.PostAsync(msg).Wait();

            if (res.Status != DreamStatus.Ok)
            {
                WriteLineToConsole("Error converting page \"" + XUri.DoubleDecode(pagePath) + "\"");
                WriteLineToLog("Edit time: " + editTime);
                WriteLineToLog("Page title: " + pageTitle);
                WriteErrorResponse(res);
                WriteErrorRequest(msg);
                Log.WarnFormat("Error converting page: '{0}'. Request: {0}    \nResponse: {1}", msg.ToString(), res.ToString());
            }
            else
            {
                XDoc createdPage = res.AsDocument();
                int  pageId      = createdPage["page/@id"].AsInt.Value;
                dekiPageUrl = createdPage["page/path"].AsText;

                return(pageId);
            }
            dekiPageUrl = null;
            return(-1);
        }
Exemple #7
0
        private void WriteErrorResponse(DreamMessage response)
        {
            WriteLineToLog("Response: " + response.ToString());
            XDoc responseDoc = response.AsDocument();

            if ((responseDoc == null) || (responseDoc.IsEmpty))
            {
                return;
            }
            XDoc messageDoc = responseDoc["message"];

            if ((messageDoc == null) || (messageDoc.IsEmpty))
            {
                return;
            }
            string messageText = messageDoc.AsText;

            if (messageText == null)
            {
                return;
            }
            WriteLineToConsole("Error: " + messageText);
        }
Exemple #8
0
        public void RatePage()
        {
            // Build ADMIN plug
            Plug p = Utils.BuildPlugForAdmin();

            // Create random page
            string       id   = null;
            string       path = null;
            DreamMessage msg  = PageUtils.CreateRandomPage(p, out id, out path);

            // Rate page a '1'
            msg = p.At("pages", id, "ratings").With("score", 1).PostAsync().Wait();
            Assert.AreEqual(DreamStatus.Ok, msg.Status, "Page rating did not return OK: " + msg.ToString());

            // Check to see if returned document elements/attributes are correct
            Assert.AreEqual(1, msg.AsDocument()["/rating/@score"].AsInt, "Unexpected computed rating");
            Assert.AreEqual(1, msg.AsDocument()["/rating/@count"].AsInt, "Unexpected rating count");
            Assert.AreEqual(1, msg.AsDocument()["/rating/user.ratedby/@score"].AsInt, "Unexpected user rating");

            // Rate page a '0'
            msg = p.At("pages", id, "ratings").With("score", 0).PostAsync().Wait();
            Assert.AreEqual(DreamStatus.Ok, msg.Status, "Page rating did not return OK: " + msg.ToString());

            // Check to see if returned document elements/attributes are correct
            Assert.AreEqual(0, msg.AsDocument()["/rating/@score"].AsInt, "Unexpected computed rating");
            Assert.AreEqual(1, msg.AsDocument()["/rating/@count"].AsInt, "Unexpected rating count");
            Assert.AreEqual(0, msg.AsDocument()["/rating/user.ratedby/@score"].AsInt, "Unexpected user rating");

            // Clear page rating
            msg = p.At("pages", id, "ratings").With("score", String.Empty).PostAsync().Wait();
            Assert.AreEqual(DreamStatus.Ok, msg.Status, "Page rating did not return OK: " + msg.ToString());

            // Check to see if returned document elements/attributes are correct
            Assert.AreEqual(String.Empty, msg.ToDocument()["@score"].AsText, "Score attribute contains a value!");
            Assert.AreEqual(0, msg.ToDocument()["@count"].AsInt, "Unrated page count does not equal 0!");

            // Delete the page
            PageUtils.DeletePageByID(p, id, true);
        }
Exemple #9
0
        private void MoveGroups()
        {
            DreamMessage msg = _dekiPlug.At("groups").With("limit", int.MaxValue).GetAsync().Wait();

            if (msg.Status != DreamStatus.Ok)
            {
                WriteLineToConsole("Error while receiving groups from Deki. Groups not converted.");
                WriteErrorResponse(msg);
                return;
            }

            Dictionary <string, string> dekiGroups = new Dictionary <string, string>();

            XDoc groupsDoc = msg.AsDocument();

            foreach (XDoc groupDoc in groupsDoc["//group"])
            {
                string dekiGroupName = groupDoc["groupname"].AsText;
                dekiGroups[dekiGroupName.ToLower()] = null;
            }

            string[] confluenceGroupNames = _confluenceService.GetGroups();

            foreach (string confluenceGroupName in confluenceGroupNames)
            {
                string dekiGroupName;
                if (!_convertedGroups.ContainsKey(confluenceGroupName.ToLower()))
                {
                    int groupNum = 0;
                    dekiGroupName = confluenceGroupName;
                    while (dekiGroups.ContainsKey(dekiGroupName.ToLower()))
                    {
                        groupNum++;
                        dekiGroupName = confluenceGroupName + groupNum.ToString();
                    }
                    if (dekiGroupName != confluenceGroupName)
                    {
                        WriteLineToConsole("Confluence group \"" + confluenceGroupName + "\" converted as \"" + dekiGroupName + "\" becouse of existing same group in Deki");
                    }

                    XDoc newGroupDoc = new XDoc("group");
                    newGroupDoc.Elem("name", dekiGroupName)
                    .Start("users");

                    foreach (ACConverterUserInfo convertedUser in _convertedUsers.Values)
                    {
                        if (Array.IndexOf(convertedUser.ConfluenceUserGroupNames, confluenceGroupName) >= 0)
                        {
                            newGroupDoc.Start("user").Attr("id", convertedUser.DekiUserId).End();
                        }
                    }

                    newGroupDoc.End();

                    Log.DebugFormat("Creating group: {0}", dekiGroupName);

                    DreamMessage res = _dekiPlug.At("groups").PostAsync(newGroupDoc).Wait();
                    if (res.Status != DreamStatus.Ok)
                    {
                        WriteLineToLog("Error converting group \"" + confluenceGroupName + "\"");
                        WriteErrorResponse(res);
                        WriteErrorRequest(newGroupDoc);
                        continue;
                    }

                    XDoc resGroupsDoc   = res.AsDocument();
                    int  newDekiGroupId = resGroupsDoc["@id"].AsInt.Value;

                    ACConverterGroupInfo convertedGroup =
                        new ACConverterGroupInfo(confluenceGroupName, dekiGroupName, newDekiGroupId);
                    _convertedGroups[confluenceGroupName.ToLower()] = convertedGroup;
                }
                else
                {
                    //This group already converted during previous ACConverter start
                    dekiGroupName = _convertedGroups[confluenceGroupName.ToLower()].DekiGroupName;

                    XDoc usersDoc = new XDoc("users");
                    foreach (ACConverterUserInfo convertedUser in _convertedUsers.Values)
                    {
                        if (Array.IndexOf(convertedUser.ConfluenceUserGroupNames, confluenceGroupName) >= 0)
                        {
                            usersDoc.Start("user").Attr("id", convertedUser.DekiUserId).End();
                        }
                    }
                    DreamMessage res = _dekiPlug.At("groups", _convertedGroups[confluenceGroupName.ToLower()].DekiGroupId.ToString(),
                                                    "users").PutAsync(usersDoc).Wait();
                    if (res.Status != DreamStatus.Ok)
                    {
                        WriteLineToLog("Error converting group's users");
                        WriteErrorResponse(res);
                        WriteErrorRequest(usersDoc);
                    }
                }
            }
        }
Exemple #10
0
        private void MoveUsers()
        {
            string[] userNames = _confluenceService.GetActiveUsers(true);

            Dictionary <string, string> dekiUsers = new Dictionary <string, string>();

            //Restore manifest from disk
            XDoc spaceManifest = GetManifestFromDisk(null) ?? new XDoc("manifest");

            DreamMessage usersResponse = _dekiPlug.At("users").With("limit", int.MaxValue).GetAsync().Wait();

            if (usersResponse.Status != DreamStatus.Ok)
            {
                WriteLineToConsole("Error while receiving users from Deki. Users not converted.");
                WriteErrorResponse(usersResponse);
                throw new DreamAbortException(usersResponse);
            }
            XDoc dekiUsersDoc = usersResponse.AsDocument();

            foreach (XDoc userDoc in dekiUsersDoc["//user"])
            {
                string dekiUserName = userDoc["nick"].AsText;
                dekiUsers[dekiUserName.ToLower()] = null;
            }

            foreach (string userName in userNames)
            {
                if (_convertedUsers.ContainsKey(userName.ToLower()))
                {
                    continue;

                    //TODO (maxm): even though a user already exists in MindTouch (perhaps created in previous run), because there is
                    // a correlated user within Confluence, the group and url mapping logic should still run.
                }

                //while user with same name exist try add number to user name.
                int    userNum     = 0;
                string newUserName = userName;
                while (dekiUsers.ContainsKey(newUserName.ToLower()))
                {
                    userNum++;
                    newUserName = userName + userNum.ToString();
                }

                if (newUserName != userName)
                {
                    WriteLineToConsole("Confluence user \"" + userName + "\" converted as \"" + newUserName + "\" becouse of existing same user in Deki");
                }

                RemoteUser confluenceUser = _confluenceService.GetUser(userName);

                XDoc usersDoc = new XDoc("user")
                                .Elem("username", newUserName)
                                .Elem("email", confluenceUser.email)
                                .Elem("fullname", confluenceUser.fullname);
                //.Start("permissions.user")
                //    .Elem("role", "Contributor")
                //.End();

                string newPassword = Guid.NewGuid().ToString();

                string[] userGroupNames = _confluenceService.GetUserGroups(confluenceUser.name);

                Log.DebugFormat("Creating user: {0} email: {1} fullname: {2}", newUserName, confluenceUser.email, confluenceUser.fullname);

                DreamMessage res = _dekiPlug.At("users").With("accountpassword", newPassword).PostAsync(usersDoc).Wait();
                if (res.Status != DreamStatus.Ok)
                {
                    WriteLineToConsole("Error converting user \"" + userName + "\"");
                    WriteErrorResponse(res);
                    WriteErrorRequest(usersDoc);
                    continue;
                }

                XDoc resUserDoc = res.AsDocument();
                int  dekiUserId = resUserDoc["@id"].AsInt.Value;
                //TODO (maxm): retrieve the actual username from the XML

                ACConverterUserInfo newUser = new ACConverterUserInfo(newUserName, newPassword, dekiUserId, userGroupNames);
                _convertedUsers[confluenceUser.name.ToLower()] = newUser;

                LogUserConversion(spaceManifest, confluenceUser.name, dekiUserId.ToString(), newUserName, confluenceUser.url);
            }

            //Save the space manifest to disk
            PersistManifestToDisk(null, spaceManifest);
        }
Exemple #11
0
        private void LoadUsersAndGroupsFromXML()
        {
            WriteLineToConsole("Reading groups and users from " + ConvertedUsersAndGroupsFileName);
            Dictionary <string, string> readedDekiUsers = new Dictionary <string, string>();
            XDoc doc = XDocFactory.LoadFrom(ConvertedUsersAndGroupsFileName, MimeType.XML);

            foreach (XDoc user in doc["//" + UserXMLTagName])
            {
                string confluenceUserName = user["@" + ConfluenceUserNameXMLAttributeName].AsText;
                string dekiName           = user["@" + DekiUserNameXMLAttributeName].AsText;

                if ((confluenceUserName == null) && (dekiName == null))
                {
                    WriteLineToConsole("Invalid XML attributes in " + ConvertedUsersAndGroupsFileName);
                    WriteLineToConsole(user.ToString());
                    continue;
                }

                if (confluenceUserName == null)
                {
                    WriteLineToConsole(ConfluenceUserNameXMLAttributeName + " not specified for " +
                                       dekiName + " in " + ConvertedUsersAndGroupsFileName + ". Record skiped.");
                    continue;
                }

                if (dekiName == null)
                {
                    WriteLineToConsole(DekiUserNameXMLAttributeName + " not specified for " +
                                       confluenceUserName + " in " + ConvertedUsersAndGroupsFileName + ". Record skiped.");
                    continue;
                }

                if (readedDekiUsers.ContainsKey(dekiName.ToLower()))
                {
                    WriteLineToConsole("Repeating entry of Deki user \"" + dekiName + "\". Record skiped.");
                    continue;
                }

                DreamMessage dekiUserMessage = _dekiPlug.At("users", "=" + Utils.DoubleUrlEncode(dekiName)).GetAsync().Wait();
                if (dekiUserMessage.Status == DreamStatus.NotFound)
                {
                    WriteLineToConsole("Deki user \"" + dekiName + "\" is specified in " + ConvertedUsersAndGroupsFileName +
                                       " but not exists in Deki. New user created.");
                    continue;
                }
                XDoc dekiUserDoc = dekiUserMessage.AsDocument();
                int  dekiUserId  = dekiUserDoc["@id"].AsInt.Value;

                string newPassword = Guid.NewGuid().ToString();

                DreamMessage pass = DreamMessage.Ok(MimeType.TEXT, newPassword);
                DreamMessage res  = _dekiPlug.At("users", dekiUserId.ToString(), "password").PutAsync(pass).Wait();
                if (res.Status != DreamStatus.Ok)
                {
                    WriteLineToConsole("Error converting user \"" + confluenceUserName + "\"");
                    WriteLineToLog("Confluence user name: " + confluenceUserName);
                    WriteLineToLog("Deki user name: " + dekiName);
                    WriteErrorResponse(res);
                    continue;
                }

                string[] userGroupNames         = new string[0];
                bool     userExistsInConfluence = _confluenceService.HasUser(confluenceUserName);
                if (userExistsInConfluence)
                {
                    userGroupNames = _confluenceService.GetUserGroups(confluenceUserName);
                }
                else
                {
                    WriteLineToConsole("Confluence user name \"" + confluenceUserName +
                                       "\" specified in " + ConvertedUsersAndGroupsFileName + " but not exists in Confluence.");
                }
                ACConverterUserInfo userInfo = new ACConverterUserInfo(dekiName, newPassword, dekiUserId,
                                                                       userGroupNames);
                if (_convertedUsers.ContainsKey(confluenceUserName.ToLower()))
                {
                    WriteLineToConsole("Repeating entry of user \"" + confluenceUserName + "\" into " + ConvertedUsersAndGroupsFileName +
                                       ". Last record used.");
                }
                _convertedUsers[confluenceUserName.ToLower()] = userInfo;
                readedDekiUsers[dekiName.ToLower()]           = confluenceUserName;
            }
            Dictionary <string, string> readedDekiGroups = new Dictionary <string, string>();

            foreach (XDoc group in doc["//" + GroupXMLTagName])
            {
                string confluenceGroupName = group["@" + ConfluenceGroupNameXMLAttributeName].AsText;
                string dekiGroupName       = group["@" + DekiGroupNameXMLAttributeName].AsText;

                if ((confluenceGroupName == null) && (dekiGroupName == null))
                {
                    WriteLineToConsole("Invalid XML attributes in " + ConvertedUsersAndGroupsFileName);
                    WriteLineToConsole(group.AsText);
                    continue;
                }

                if (confluenceGroupName == null)
                {
                    WriteLineToConsole(ConfluenceGroupNameXMLAttributeName + " not specified for \"" +
                                       dekiGroupName + "\" in " + ConvertedUsersAndGroupsFileName + ". Record skiped.");
                    continue;
                }

                if (dekiGroupName == null)
                {
                    WriteLineToConsole(DekiGroupNameXMLAttributeName + " not specified for \"" +
                                       confluenceGroupName + "\" in " + ConvertedUsersAndGroupsFileName + ". Record skiped.");
                    continue;
                }

                if (readedDekiGroups.ContainsKey(dekiGroupName.ToLower()))
                {
                    WriteLineToConsole("Repeating entry of Deki group \"" + dekiGroupName + "\". Record skiped.");
                    continue;
                }

                dekiGroupName = dekiGroupName.Replace(" ", "_");
                DreamMessage dekiGroupMessage = _dekiPlug.At("groups", "=" + dekiGroupName).GetAsync().Wait();
                if (dekiGroupMessage.Status == DreamStatus.NotFound)
                {
                    WriteLineToConsole("Deki group \"" + dekiGroupName + "\" is specified in " + ConvertedUsersAndGroupsFileName +
                                       " but not exists in Deki. New group created.");
                    continue;
                }
                XDoc dekiGroupDoc = dekiGroupMessage.AsDocument();
                int  dekiGroupId  = dekiGroupDoc["@id"].AsInt.Value;

                ACConverterGroupInfo groupInfo = new ACConverterGroupInfo(confluenceGroupName,
                                                                          dekiGroupName, dekiGroupId);
                if (_convertedUsers.ContainsKey(confluenceGroupName.ToLower()))
                {
                    WriteLineToConsole("Repeating entry of group \"" + confluenceGroupName + "\" into " + ConvertedUsersAndGroupsFileName +
                                       ". Last record used.");
                }
                _convertedGroups[confluenceGroupName.ToLower()] = groupInfo;
            }
            WriteLineToConsole("Users and groups readed!");
        }
        public void MoveAttachments(XDoc spaceManifest, int dekiPageID, long confluencePageId)
        {
            RemoteAttachment[] attachments = _confluenceService.GetAttachments(confluencePageId);

            int count = attachments.Length;

            foreach (RemoteAttachment attachment in attachments)
            {
                // This was when a single attachment (the latest) was being handled
                // byte[] attachmentData;
                Log.DebugFormat("Processing file: {0} size: {1} #remaining: {2}", attachment.fileName, attachment.fileSize, --count);

                Plug         p   = (attachment.creator == null) ? _dekiPlug : GetPlugForConvertedUser(attachment.creator);
                DreamMessage res = p.At("pages", dekiPageID.ToString(), "files", "=" + Utils.DoubleUrlEncode(attachment.fileName), "info")
                                   .GetAsync().Wait();

                if (res.Status == DreamStatus.Ok)
                {
                    Log.DebugFormat("Already converted: {0} MindTouch URL: {1}", attachment.fileName, res.AsDocument()["contents/@href"].AsText);
                }
                else
                {
                    MimeType attachmentMimeType;
                    if (!MimeType.TryParse(attachment.contentType, out attachmentMimeType))
                    {
                        attachmentMimeType = MimeType.FromFileExtension(attachment.fileName);
                    }

                    // The attachment URL contains the latest actual version of this attachment e.g.
                    // http://confluencesite.com/download/attachments/3604492/excelspreadsheet.xls?version=1

                    int latestVersion = 1, oldestVersion = 1;
                    if (attachment.url.Contains("version="))
                    {
                        try
                        {
                            latestVersion = ParseVersionFromUri(attachment.url);
                        }
                        catch {}
                    }

                    try
                    {
                        if (latestVersion > 1)
                        {
                            if ((latestVersion - 5) > 1)
                            {
                                oldestVersion = latestVersion - 5;
                            }
                        }

                        for (int x = oldestVersion; x <= latestVersion; x++)
                        {
                            try
                            {
                                byte[]       ThisAttachmentData = _confluenceService.GetAttachmentData(confluencePageId, attachment.fileName, x);
                                DreamMessage msg = new DreamMessage(DreamStatus.Ok, null, attachmentMimeType, ThisAttachmentData);
                                string       AttachmentTimeStampComment = attachment.comment + " - attachment version " + x + " originally created on " + attachment.created.Value.ToShortDateString() + " " + attachment.created.Value.ToShortTimeString();

                                res = p.At("pages", dekiPageID.ToString(), "files", "=" + Utils.DoubleUrlEncode(attachment.fileName))
                                      .With("description", AttachmentTimeStampComment)
                                      .PutAsync(msg).Wait();

                                if (res.Status != DreamStatus.Ok)
                                {
                                    Log.WarnFormat("File '{0}' version '{1}' on Confluence pageid '{2}' not converted: {3}", attachment.fileName, x, attachment.pageId, res.ToString());
                                    // added as suggested by Max on the list created here http://projects.mindtouch.com/User:emilyp/Booze_Allen/Conversion_Issues
                                    throw new DreamAbortException(res);
                                }

                                XDoc   resDoc     = res.ToDocument();
                                string contentUrl = resDoc["contents/@href"].AsText;

                                LogFileConversion(spaceManifest, attachment, contentUrl);
                            }
                            catch (DreamAbortException dEx)
                            {
                                WriteLineToConsole("Error on moving attachment " + attachment.fileName + "version " + x);
                                if (!String.IsNullOrEmpty(dEx.Message))
                                {
                                    WriteLineToLog(dEx.Message);
                                }
                                continue;
                            }
                            catch (System.Web.Services.Protocols.SoapException e)
                            {
                                WriteLineToConsole("Error obtaining attachment data from confluence " + attachment.fileName + "version " + x);
                                if ((e.Detail != null) && (e.Detail.OuterXml != null))
                                {
                                    WriteLineToLog(e.Detail.OuterXml);
                                }
                                continue;
                            }
                        } // for loop to submit revisions
                    }
                    catch (System.Web.Services.Protocols.SoapException e)
                    {
                        WriteLineToConsole("Error on moving attachment " + attachment.fileName);
                        if ((e.Detail != null) && (e.Detail.OuterXml != null))
                        {
                            WriteLineToLog(e.Detail.OuterXml);
                        }
                        continue;
                    }
                }
            }
        }