Fix bug where loading an OAR with a deeded parcel would always set the parcel owner ID to the estate owner even if the group UUID was present.

Aims to address http://opensimulator.org/mantis/view.php?id=6355
As part of this work, an incomplete IXGroupsData was added which currently only allows store/fetch/delete of group records
(i.e. no membership data etc)
This is subject to change and currently only an in-memory storage implementation exists for regression test purposes.
connector_plugin
Justin Clark-Casey (justincc) 2012-11-24 02:43:31 +00:00
parent cda531bc3c
commit 82690e1384
14 changed files with 613 additions and 240 deletions

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Data
{
public class XGroup
{
public UUID groupID;
public UUID ownerRoleID;
public string name;
public string charter;
public bool showInList;
public UUID insigniaID;
public int membershipFee;
public bool openEnrollment;
public bool allowPublish;
public bool maturePublish;
public UUID founderID;
public ulong everyonePowers;
public ulong ownersPowers;
public XGroup Clone()
{
return (XGroup)MemberwiseClone();
}
}
/// <summary>
/// Early stub interface for groups data, not final.
/// </summary>
/// <remarks>
/// Currently in-use only for regression test purposes. Needs to be filled out over time.
/// </remarks>
public interface IXGroupData
{
bool StoreGroup(XGroup group);
XGroup[] GetGroups(string field, string val);
XGroup[] GetGroups(string[] fields, string[] vals);
bool DeleteGroups(string field, string val);
bool DeleteGroups(string[] fields, string[] vals);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Data;
namespace OpenSim.Data.Null
{
/// <summary>
/// Not a proper generic data handler yet - probably needs to actually store the data as well instead of relying
/// on descendent classes
/// </summary>
public class NullGenericDataHandler
{
protected List<T> Get<T>(string[] fields, string[] vals, List<T> inputEntities)
{
List<T> entities = inputEntities;
for (int i = 0; i < fields.Length; i++)
{
entities
= entities.Where(
e =>
{
FieldInfo fi = typeof(T).GetField(fields[i]);
if (fi == null)
throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i]));
return fi.GetValue(e).ToString() == vals[i];
}
).ToList();
}
return entities;
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Data;
namespace OpenSim.Data.Null
{
public class NullXGroupData : NullGenericDataHandler, IXGroupData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Dictionary<UUID, XGroup> m_groups = new Dictionary<UUID, XGroup>();
public NullXGroupData(string connectionString, string realm) {}
public bool StoreGroup(XGroup group)
{
lock (m_groups)
{
m_groups[group.groupID] = group.Clone();
}
return true;
}
public XGroup[] GetGroups(string field, string val)
{
return GetGroups(new string[] { field }, new string[] { val });
}
public XGroup[] GetGroups(string[] fields, string[] vals)
{
lock (m_groups)
{
List<XGroup> origGroups = Get<XGroup>(fields, vals, m_groups.Values.ToList());
return origGroups.Select(g => g.Clone()).ToArray();
}
}
public bool DeleteGroups(string field, string val)
{
return DeleteGroups(new string[] { field }, new string[] { val });
}
public bool DeleteGroups(string[] fields, string[] vals)
{
lock (m_groups)
{
XGroup[] groupsToDelete = GetGroups(fields, vals);
Array.ForEach(groupsToDelete, g => m_groups.Remove(g.groupID));
}
return true;
}
}
}

View File

@ -154,6 +154,11 @@ namespace OpenSim.Framework.Serialization
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
}
public static string CreateOarLandDataPath(LandData ld)
{
return string.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, ld.GlobalID);
}
/// <summary>
/// Create the filename used to store an object in an OpenSim Archive.
/// </summary>

View File

@ -552,19 +552,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// Validate User and Group UUID's
if (parcel.IsGroupOwned)
{
if (!ResolveGroupUuid(parcel.GroupID))
{
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
parcel.GroupID = UUID.Zero;
parcel.IsGroupOwned = false;
}
}
else
{
if (!ResolveUserUuid(scene, parcel.OwnerID))
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
if (!ResolveGroupUuid(parcel.GroupID))
{
// m_log.DebugFormat("[ARCHIVE READ REQUEST]: Could not find group {0}", parcel.GroupID);
parcel.GroupID = UUID.Zero;
parcel.IsGroupOwned = false;
}
// else
// {
// m_log.DebugFormat("[ARCHIVE READ REQUEST]: Found group {0}", parcel.GroupID);
// }
List<LandAccessEntry> accessList = new List<LandAccessEntry>();
foreach (LandAccessEntry entry in parcel.ParcelAccessList)
@ -576,8 +580,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
parcel.ParcelAccessList = accessList;
// m_log.DebugFormat(
// "[ARCHIVER]: Adding parcel {0}, local id {1}, area {2}",
// parcel.Name, parcel.LocalID, parcel.Area);
// "[ARCHIVER]: Adding parcel {0}, local id {1}, owner {2}, group {3}, isGroupOwned {4}, area {5}",
// parcel.Name, parcel.LocalID, parcel.OwnerID, parcel.GroupID, parcel.IsGroupOwned, parcel.Area);
landData.Add(parcel);
}

View File

@ -167,7 +167,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
}
scenesGroup.CalcSceneLocations();
m_archiveWriter = new TarArchiveWriter(m_saveStream);
try
@ -216,7 +215,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
}
}
private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
{
m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
@ -540,7 +538,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
}
protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
{
if (regionDir != string.Empty)
@ -560,8 +557,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
foreach (ILandObject lo in landObjects)
{
LandData landData = lo.LandData;
string landDataPath = String.Format("{0}{1}{2}.xml",
regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
string landDataPath
= String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData));
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
}
@ -605,7 +602,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
CloseArchive(String.Empty);
}
/// <summary>
/// Closes the archive and notifies that we're done.
/// </summary>
@ -629,6 +625,5 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
}
}
}

View File

@ -31,16 +31,19 @@ using System.IO;
using System.Reflection;
using System.Threading;
using log4net.Config;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenMetaverse.Assets;
using OpenSim.Framework;
using OpenSim.Framework.Serialization;
using OpenSim.Framework.Serialization.External;
using OpenSim.Region.CoreModules.World.Land;
using OpenSim.Region.CoreModules.World.Serialiser;
using OpenSim.Region.CoreModules.World.Terrain;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization;
using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
@ -128,6 +131,53 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName };
}
private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
{
SceneObjectPart part1 = CreateSceneObjectPart1();
sog1 = new SceneObjectGroup(part1);
scene.AddNewSceneObject(sog1, false);
AssetNotecard nc = new AssetNotecard();
nc.BodyText = "Hello World!";
nc.Encode();
ncAssetUuid = UUID.Random();
UUID ncItemUuid = UUID.Random();
AssetBase ncAsset
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
m_scene.AssetService.Store(ncAsset);
TaskInventoryItem ncItem
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
SceneObjectPart part2 = CreateSceneObjectPart2();
sog2 = new SceneObjectGroup(part2);
part2.Inventory.AddInventoryItem(ncItem, true);
scene.AddNewSceneObject(sog2, false);
}
private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
{
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
{
using (BinaryReader br = new BinaryReader(resource))
{
// FIXME: Use the inspector instead
soundData = br.ReadBytes(99999999);
soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
string soundAssetFileName
= ArchiveConstants.ASSETS_PATH + soundUuid
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
tar.WriteFile(soundAssetFileName, soundData);
/*
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
scene.AssetService.Store(soundAsset);
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
*/
}
}
}
/// <summary>
/// Test saving an OpenSim Region Archive.
/// </summary>
@ -204,30 +254,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
// TODO: Test presence of more files and contents of files.
}
private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
{
SceneObjectPart part1 = CreateSceneObjectPart1();
sog1 = new SceneObjectGroup(part1);
scene.AddNewSceneObject(sog1, false);
AssetNotecard nc = new AssetNotecard();
nc.BodyText = "Hello World!";
nc.Encode();
ncAssetUuid = UUID.Random();
UUID ncItemUuid = UUID.Random();
AssetBase ncAsset
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
m_scene.AssetService.Store(ncAsset);
TaskInventoryItem ncItem
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
SceneObjectPart part2 = CreateSceneObjectPart2();
sog2 = new SceneObjectGroup(part2);
part2.Inventory.AddInventoryItem(ncItem, true);
scene.AddNewSceneObject(sog2, false);
}
/// <summary>
/// Test saving an OpenSim Region Archive with the no assets option
/// </summary>
@ -308,59 +334,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
// TODO: Test presence of more files and contents of files.
}
/// <summary>
/// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
/// 2 can come after 3).
/// </summary>
[Test]
public void TestLoadOarUnorderedParts()
{
TestHelpers.InMethod();
UUID ownerId = TestHelpers.ParseTail(0xaaaa);
MemoryStream archiveWriteStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
tar.WriteFile(
ArchiveConstants.CONTROL_FILE_PATH,
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
SceneObjectPart sop2
= SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
SceneObjectPart sop3
= SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
// Add the parts so they will be written out in reverse order to the oar
sog1.AddPart(sop3);
sop3.LinkNum = 3;
sog1.AddPart(sop2);
sop2.LinkNum = 2;
tar.WriteFile(
ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
SceneObjectSerializer.ToXml2Format(sog1));
tar.Close();
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
lock (this)
{
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
m_archiverModule.DearchiveRegion(archiveReadStream);
}
Assert.That(m_lastErrorMessage, Is.Null);
SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
Assert.That(part2.LinkNum, Is.EqualTo(2));
SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
Assert.That(part3.LinkNum, Is.EqualTo(3));
}
/// <summary>
/// Test loading an OpenSim Region Archive.
/// </summary>
@ -435,50 +408,57 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
TestLoadedRegion(part1, soundItemName, soundData);
}
private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
/// <summary>
/// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g.
/// 2 can come after 3).
/// </summary>
[Test]
public void TestLoadOarUnorderedParts()
{
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
{
using (BinaryReader br = new BinaryReader(resource))
{
// FIXME: Use the inspector instead
soundData = br.ReadBytes(99999999);
soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
string soundAssetFileName
= ArchiveConstants.ASSETS_PATH + soundUuid
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
tar.WriteFile(soundAssetFileName, soundData);
TestHelpers.InMethod();
/*
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
scene.AssetService.Store(soundAsset);
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
*/
}
}
UUID ownerId = TestHelpers.ParseTail(0xaaaa);
MemoryStream archiveWriteStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
tar.WriteFile(
ArchiveConstants.CONTROL_FILE_PATH,
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
SceneObjectPart sop2
= SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
SceneObjectPart sop3
= SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
// Add the parts so they will be written out in reverse order to the oar
sog1.AddPart(sop3);
sop3.LinkNum = 3;
sog1.AddPart(sop2);
sop2.LinkNum = 2;
tar.WriteFile(
ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
SceneObjectSerializer.ToXml2Format(sog1));
tar.Close();
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
lock (this)
{
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
m_archiverModule.DearchiveRegion(archiveReadStream);
}
private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
{
SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
Assert.That(m_lastErrorMessage, Is.Null);
Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
Assert.That(
object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
Assert.That(
object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
Assert.That(part2.LinkNum, Is.EqualTo(2));
TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
Assert.That(part3.LinkNum, Is.EqualTo(3));
}
/// <summary>
@ -562,6 +542,81 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
}
}
/// <summary>
/// Test OAR loading where the land parcel is group deeded.
/// </summary>
/// <remarks>
/// In this situation, the owner ID is set to the group ID.
/// </remarks>
[Test]
public void TestLoadOarDeededLand()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
UUID landID = TestHelpers.ParseTail(0x10);
MockGroupsServicesConnector groupsService = new MockGroupsServicesConnector();
IConfigSource configSource = new IniConfigSource();
IConfig config = configSource.AddConfig("Groups");
config.Set("Enabled", true);
config.Set("Module", "GroupsModule");
config.Set("DebugEnabled", true);
SceneHelpers.SetupSceneModules(
m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() });
// Create group in scene for loading
// FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests.
UUID groupID
= groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero);
// Construct OAR
MemoryStream oarStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter(oarStream);
tar.WriteDir(ArchiveConstants.LANDDATA_PATH);
tar.WriteFile(
ArchiveConstants.CONTROL_FILE_PATH,
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
LandObject lo = new LandObject(groupID, true, null);
// FIXME: We set directly rather than call SetLandBitmap in order not to do an AABB value update, which
// requests the terrain heightmap from an active scene. This is confusing and not a long-term solution.
//lo.LandBitmap = lo.BasicFullRegionLandBitmap();
lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
// FIXME: We have to make a separate call to update the LandData's copy of the land bitmap, even though this is
// identical to the LandObject copy. This should be changed so there's only one copy of the data if at all
// possible
//lo.UpdateLandBitmapByteArray();
LandData ld = lo.LandData;
ld.GlobalID = landID;
string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, null));
tar.Close();
oarStream = new MemoryStream(oarStream.ToArray());
// Load OAR
lock (this)
{
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
m_archiverModule.DearchiveRegion(oarStream);
}
ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16);
LandData rLd = rLo.LandData;
Assert.That(rLd.GlobalID, Is.EqualTo(landID));
Assert.That(rLd.OwnerID, Is.EqualTo(groupID));
Assert.That(rLd.GroupID, Is.EqualTo(groupID));
Assert.That(rLd.IsGroupOwned, Is.EqualTo(true));
}
/// <summary>
/// Test loading the region settings of an OpenSim Region Archive.
/// </summary>
@ -781,9 +836,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
}
}
// Save OAR
MemoryStream archiveWriteStream = new MemoryStream();
m_scene.EventManager.OnOarFileSaved += SaveCompleted;
@ -800,7 +853,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
// Check that the OAR contains the expected data
Assert.That(m_lastRequestId, Is.EqualTo(requestId));
byte[] archive = archiveWriteStream.ToArray();
@ -976,5 +1028,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
TestLoadedRegion(part1, soundItemName, soundData);
}
private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
{
SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
Assert.That(
object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal");
Assert.That(
object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
}
}
}

View File

@ -1378,11 +1378,12 @@ namespace OpenSim.Region.CoreModules.World.Land
public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
{
// m_log.DebugFormat(
// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
for (int i = 0; i < data.Count; i++)
{
IncomingLandObjectFromStorage(data[i]);
}
}
public void IncomingLandObjectFromStorage(LandData data)
{

View File

@ -727,9 +727,10 @@ namespace OpenSim.Region.CoreModules.World.Land
int ty = min_y * 4;
if (ty > ((int)Constants.RegionSize - 1))
ty = ((int)Constants.RegionSize - 1);
LandData.AABBMin =
new Vector3((float) (min_x * 4), (float) (min_y * 4),
(float) m_scene.Heightmap[tx, ty]);
new Vector3(
(float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
tx = max_x * 4;
if (tx > ((int)Constants.RegionSize - 1))
@ -737,9 +738,11 @@ namespace OpenSim.Region.CoreModules.World.Land
ty = max_y * 4;
if (ty > ((int)Constants.RegionSize - 1))
ty = ((int)Constants.RegionSize - 1);
LandData.AABBMax =
new Vector3((float) (max_x * 4), (float) (max_y * 4),
(float) m_scene.Heightmap[tx, ty]);
LandData.AABBMax
= new Vector3(
(float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
LandData.Area = tempArea;
}

View File

@ -36,7 +36,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
{
UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID);
void UpdateGroup(UUID RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish);
/// <summary>
/// Get the group record.
/// </summary>
/// <returns></returns>
/// <param name='RequestingAgentID'>The UUID of the user making the request.</param>
/// <param name='GroupID'>
/// The ID of the record to retrieve.
/// GroupName may be specified instead, in which case this parameter will be UUID.Zero
/// </param>
/// <param name='GroupName'>
/// The name of the group to retrieve.
/// GroupID may be specified instead, in which case this parmeter will be null.
/// </param>
GroupRecord GetGroupRecord(UUID RequestingAgentID, UUID GroupID, string GroupName);
List<DirGroupsReplyData> FindGroups(UUID RequestingAgentID, string search);
List<GroupMembersData> GetGroupMembers(UUID RequestingAgentID, UUID GroupID);

View File

@ -54,13 +54,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
private bool m_debugEnabled = false;
public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome |
GroupPowers.Accountable |
GroupPowers.JoinChat |
GroupPowers.AllowVoiceChat |
GroupPowers.ReceiveNotices |
GroupPowers.StartProposal |
GroupPowers.VoteOnProposal;
public const GroupPowers DefaultEveryonePowers
= GroupPowers.AllowSetHome
| GroupPowers.Accountable
| GroupPowers.JoinChat
| GroupPowers.AllowVoiceChat
| GroupPowers.ReceiveNotices
| GroupPowers.StartProposal
| GroupPowers.VoteOnProposal;
// Would this be cleaner as (GroupPowers)ulong.MaxValue?
public const GroupPowers DefaultOwnerPowers
= GroupPowers.Accountable
| GroupPowers.AllowEditLand
| GroupPowers.AllowFly
| GroupPowers.AllowLandmark
| GroupPowers.AllowRez
| GroupPowers.AllowSetHome
| GroupPowers.AllowVoiceChat
| GroupPowers.AssignMember
| GroupPowers.AssignMemberLimited
| GroupPowers.ChangeActions
| GroupPowers.ChangeIdentity
| GroupPowers.ChangeMedia
| GroupPowers.ChangeOptions
| GroupPowers.CreateRole
| GroupPowers.DeedObject
| GroupPowers.DeleteRole
| GroupPowers.Eject
| GroupPowers.FindPlaces
| GroupPowers.Invite
| GroupPowers.JoinChat
| GroupPowers.LandChangeIdentity
| GroupPowers.LandDeed
| GroupPowers.LandDivideJoin
| GroupPowers.LandEdit
| GroupPowers.LandEjectAndFreeze
| GroupPowers.LandGardening
| GroupPowers.LandManageAllowed
| GroupPowers.LandManageBanned
| GroupPowers.LandManagePasses
| GroupPowers.LandOptions
| GroupPowers.LandRelease
| GroupPowers.LandSetSale
| GroupPowers.ModerateChat
| GroupPowers.ObjectManipulate
| GroupPowers.ObjectSetForSale
| GroupPowers.ReceiveNotices
| GroupPowers.RemoveMember
| GroupPowers.ReturnGroupOwned
| GroupPowers.ReturnGroupSet
| GroupPowers.ReturnNonGroup
| GroupPowers.RoleProperties
| GroupPowers.SendNotices
| GroupPowers.SetLandingPoint
| GroupPowers.StartProposal
| GroupPowers.VoteOnProposal;
private bool m_connectorEnabled = false;
@ -219,59 +268,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
param["AllowPublish"] = allowPublish == true ? 1 : 0;
param["MaturePublish"] = maturePublish == true ? 1 : 0;
param["FounderID"] = founderID.ToString();
param["EveryonePowers"] = ((ulong)m_DefaultEveryonePowers).ToString();
param["EveryonePowers"] = ((ulong)DefaultEveryonePowers).ToString();
param["OwnerRoleID"] = OwnerRoleID.ToString();
// Would this be cleaner as (GroupPowers)ulong.MaxValue;
GroupPowers OwnerPowers = GroupPowers.Accountable
| GroupPowers.AllowEditLand
| GroupPowers.AllowFly
| GroupPowers.AllowLandmark
| GroupPowers.AllowRez
| GroupPowers.AllowSetHome
| GroupPowers.AllowVoiceChat
| GroupPowers.AssignMember
| GroupPowers.AssignMemberLimited
| GroupPowers.ChangeActions
| GroupPowers.ChangeIdentity
| GroupPowers.ChangeMedia
| GroupPowers.ChangeOptions
| GroupPowers.CreateRole
| GroupPowers.DeedObject
| GroupPowers.DeleteRole
| GroupPowers.Eject
| GroupPowers.FindPlaces
| GroupPowers.Invite
| GroupPowers.JoinChat
| GroupPowers.LandChangeIdentity
| GroupPowers.LandDeed
| GroupPowers.LandDivideJoin
| GroupPowers.LandEdit
| GroupPowers.LandEjectAndFreeze
| GroupPowers.LandGardening
| GroupPowers.LandManageAllowed
| GroupPowers.LandManageBanned
| GroupPowers.LandManagePasses
| GroupPowers.LandOptions
| GroupPowers.LandRelease
| GroupPowers.LandSetSale
| GroupPowers.ModerateChat
| GroupPowers.ObjectManipulate
| GroupPowers.ObjectSetForSale
| GroupPowers.ReceiveNotices
| GroupPowers.RemoveMember
| GroupPowers.ReturnGroupOwned
| GroupPowers.ReturnGroupSet
| GroupPowers.ReturnNonGroup
| GroupPowers.RoleProperties
| GroupPowers.SendNotices
| GroupPowers.SetLandingPoint
| GroupPowers.StartProposal
| GroupPowers.VoteOnProposal;
param["OwnersPowers"] = ((ulong)OwnerPowers).ToString();
param["OwnersPowers"] = ((ulong)DefaultOwnerPowers).ToString();
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.createGroup", param);
@ -612,8 +611,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
}
return Roles;
}
public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID GroupID)
@ -676,7 +673,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
}
return members;
}
public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID GroupID)
@ -727,9 +723,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
values.Add(data);
}
}
return values;
return values;
}
public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID)
{
Hashtable param = new Hashtable();
@ -737,7 +734,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
Hashtable respData = XmlRpcCall(requestingAgentID, "groups.getGroupNotice", param);
if (respData.Contains("error"))
{
return null;
@ -761,6 +757,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
return data;
}
public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket)
{
string binBucket = OpenMetaverse.Utils.BytesToHexString(binaryBucket, "");
@ -777,8 +774,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
XmlRpcCall(requestingAgentID, "groups.addGroupNotice", param);
}
#endregion
#region GroupSessionTracking

View File

@ -26,12 +26,15 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Data;
using OpenSim.Data.Null;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
@ -44,6 +47,8 @@ namespace OpenSim.Tests.Common.Mock
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
IXGroupData m_data = new NullXGroupData(null, null);
public string Name
{
get { return "MockGroupsServicesConnector"; }
@ -84,8 +89,34 @@ namespace OpenSim.Tests.Common.Mock
int membershipFee, bool openEnrollment, bool allowPublish,
bool maturePublish, UUID founderID)
{
XGroup group = new XGroup()
{
groupID = UUID.Random(),
ownerRoleID = UUID.Random(),
name = name,
charter = charter,
showInList = showInList,
insigniaID = insigniaID,
membershipFee = membershipFee,
openEnrollment = openEnrollment,
allowPublish = allowPublish,
maturePublish = maturePublish,
founderID = founderID,
everyonePowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultEveryonePowers,
ownersPowers = (ulong)XmlRpcGroupsServicesConnectorModule.DefaultOwnerPowers
};
if (m_data.StoreGroup(group))
{
m_log.DebugFormat("[MOCK GROUPS SERVICES CONNECTOR]: Created group {0} {1}", group.name, group.groupID);
return group.groupID;
}
else
{
m_log.ErrorFormat("[MOCK GROUPS SERVICES CONNECTOR]: Failed to create group {0}", name);
return UUID.Zero;
}
}
public void UpdateGroup(UUID requestingAgentID, UUID groupID, string charter, bool showInList,
UUID insigniaID, int membershipFee, bool openEnrollment,
@ -107,9 +138,49 @@ namespace OpenSim.Tests.Common.Mock
{
}
public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID GroupID, string GroupName)
public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID groupID, string groupName)
{
m_log.DebugFormat(
"[MOCK GROUPS SERVICES CONNECTOR]: Processing GetGroupRecord() for groupID {0}, name {1}",
groupID, groupName);
XGroup[] groups;
string field, val;
if (groupID != UUID.Zero)
{
field = "groupID";
val = groupID.ToString();
}
else
{
field = "name";
val = groupName;
}
groups = m_data.GetGroups(field, val);
if (groups.Length == 0)
return null;
XGroup xg = groups[0];
GroupRecord gr = new GroupRecord()
{
GroupID = xg.groupID,
GroupName = xg.name,
AllowPublish = xg.allowPublish,
MaturePublish = xg.maturePublish,
Charter = xg.charter,
FounderID = xg.founderID,
// FIXME: group picture storage location unknown
MembershipFee = xg.membershipFee,
OpenEnrollment = xg.openEnrollment,
OwnerRoleID = xg.ownerRoleID,
ShowInList = xg.showInList
};
return gr;
}
public GroupProfileData GetMemberGroupProfile(UUID requestingAgentID, UUID GroupID, UUID AgentID)

View File

@ -33,10 +33,11 @@ using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Data.Null;
namespace OpenSim.Tests.Common.Mock
{
public class TestXInventoryDataPlugin : IXInventoryData
public class TestXInventoryDataPlugin : NullGenericDataHandler, IXInventoryData
{
private Dictionary<UUID, XInventoryFolder> m_allFolders = new Dictionary<UUID, XInventoryFolder>();
private Dictionary<UUID, XInventoryItem> m_allItems = new Dictionary<UUID, XInventoryItem>();
@ -58,28 +59,6 @@ namespace OpenSim.Tests.Common.Mock
return origFolders.Select(f => f.Clone()).ToArray();
}
private List<T> Get<T>(string[] fields, string[] vals, List<T> inputEntities)
{
List<T> entities = inputEntities;
for (int i = 0; i < fields.Length; i++)
{
entities
= entities.Where(
e =>
{
FieldInfo fi = typeof(T).GetField(fields[i]);
if (fi == null)
throw new NotImplementedException(string.Format("No field {0} for val {1}", fields[i], vals[i]));
return fi.GetValue(e).ToString() == vals[i];
}
).ToList();
}
return entities;
}
public bool StoreFolder(XInventoryFolder folder)
{
m_allFolders[folder.folderID] = folder.Clone();

View File

@ -1676,6 +1676,7 @@
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="System.Core"/>
<Reference name="System.Xml"/>
<Reference name="OpenSim.Data"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
@ -2683,12 +2684,13 @@
<Reference name="nunit.framework" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenSim.Data"/>
<Reference name="OpenSim.Data.Null"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Communications"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Data"/>
<Reference name="OpenSim.Services.Interfaces"/>
<Reference name="OpenSim.Server.Base"/>
<Reference name="OpenSim.Region.Framework"/>
@ -2980,6 +2982,7 @@
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Region.OptionalModules"/>
<Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="OpenSim.Region.ScriptEngine.Shared"/>
<Reference name="OpenSim.Region.ScriptEngine.XEngine"/>