Merge 5e5a66bf92aee119cd809c5239cd54062b698380 into 83526569c1341353f2f63c2fa8d902dc0ddfd94f

This commit is contained in:
Hipposgrumm 2025-11-20 19:22:58 +01:00 committed by GitHub
commit 4889f11214
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 1258 additions and 81 deletions

View File

@ -79,13 +79,13 @@ Almost everything:
- hideouts
- farms
- minigames
- clans
- MMO (using sodoff-mmo)
### What doesn't work
- play as Guest
- friends
- clans
- in-game messaging system (Terrible Mail)
@ -94,10 +94,13 @@ Almost everything:
#### Fully implemented
- AcceptMission
- AddBattleItems
- AssignRole
- AuthenticateUser
- CreateGroup
- CreatePet
- DeleteAccountNotification
- DeleteProfile
- EditGroup
- FuseItems
- GetAchievementsByUserID
- GetAllActivePetsByuserId
@ -108,12 +111,17 @@ Almost everything:
- GetDetailedChildList
- GetGameData
- GetGameDataByUser
- GetGroups
- GetGroupsByGroupType
- GetGroupsByUserID
- GetImage
- GetImageByUserId
- GetItem
- GetKeyValuePair
- GetKeyValuePairByUserID
- GetMembersByGroupID
- GetMMOServerInfoWithZone (uses resource xml as response)
- GetPendingJoinRequests
- GetPetAchievementsByUserID
- GetSelectedRaisedPet
- GetStore
@ -127,6 +135,8 @@ Almost everything:
- GetUserRoomItemPositions
- GetUserUpcomingMissionState
- IsValidApiToken_V2
- JoinGroup (V1 & V2) (User-given message for join request disabled, at least for now)
- LeaveGroup
- LoginChild
- LoginParent
- PurchaseItems (V1)
@ -152,7 +162,6 @@ Almost everything:
#### Implemented enough (probably)
- GetCommonInventory (V1 - returns the viking's inventory if it is called with a viking; otherwise returns 8 viking slots)
- GetGroupsByGroupType (only useful for Eat My Dust at the moment)
- GetQuestions (doesn't return all questions, probably doesn't need to)
- GetRules (doesn't return any rules, probably doesn't need to)
- GetSubscriptionInfo (always returns member, with end date 10 years from now)
@ -171,7 +180,6 @@ Almost everything:
- GetTopAchievementPointUsers (ignores type [all, buddy, hall of fame, ...] and mode [overall, monthly, weekly] properties)
- GetUserAchievements (used by Magic & Mythies)
- GetUserRoomList (room categories are not implemented, but it's enough for SoD)
- JoinGroup (for Eat My Dust only)
- ProcessRewardedItems (gives gems, but doesn't give gold, gold is not yet implemented)
- SellItems (gives gems, but doesn't give gold, gold is not yet implemented)
- SetUserAchievementTask (returns a real reward but still use task placeholder)

View File

@ -201,17 +201,23 @@ public class ContentController : Controller {
// Check if name populated
NameValidationRequest request = XmlUtil.DeserializeXml<NameValidationRequest>(nameValidationRequest);
if (request.Category == NameCategory.Default) {
// This is an avatar we are checking
// Check if viking exists
bool exists = ctx.Vikings.Count(e => e.Name == request.Name) > 0;
NameValidationResult result = exists ? NameValidationResult.NotUnique : NameValidationResult.Ok;
return Ok(new NameValidationResponse { Result = result});
} else {
// TODO: pets, groups, default
return Ok();
bool exists;
switch (request.Category) {
case NameCategory.Default:
// This is an avatar we are checking
// Check if viking exists
exists = ctx.Vikings.Any(e => e.Name == request.Name);
break;
case NameCategory.Group:
exists = ctx.Groups.Any(e => e.Name == request.Name);
break;
default:
// TODO: pets, default
return Ok();
}
NameValidationResult result = exists ? NameValidationResult.NotUnique : NameValidationResult.Ok;
return Ok(new NameValidationResponse { Result = result });
}
[HttpPost]

View File

@ -3,9 +3,85 @@ using sodoff.Attributes;
using sodoff.Model;
using sodoff.Schema;
using sodoff.Util;
using GroupMember = sodoff.Model.GroupMember;
namespace sodoff.Controllers.Common;
public class GroupController : Controller {
// Any permission that is commented out is not implemented.
private static readonly List<string> PermissionsMember = [
//"Delete Own Msg",
//"Post Message"
];
private static readonly List<string> PermissionsElder = [
//"Invite",
"Approve Join Request",
//"Post News",
//"Delete Own Msg",
//"Delete Any Msg",
//"Delete News",
//"Post Message",
"Remove Member"
];
private static readonly List<string> PermissionsLeader = [
//"Invite",
"Approve Join Request",
"Assign Leader",
"Assign Elder",
"Demote Elder",
"Edit Group",
//"Post News",
//"Delete Own Msg",
//"Delete Any Msg",
//"Delete News",
//"Post Message",
"Remove Member"
];
private static readonly List<RolePermission> RolePermissions = [
new RolePermission {
GroupType = GroupType.Public,
Role = UserRole.Member,
Permissions = PermissionsMember
}, new RolePermission {
GroupType = GroupType.Public,
Role = UserRole.Elder,
Permissions = PermissionsElder
}, new RolePermission {
GroupType = GroupType.Public,
Role = UserRole.Leader,
Permissions = PermissionsLeader
},
new RolePermission {
GroupType = GroupType.MembersOnly,
Role = UserRole.Member,
Permissions = PermissionsMember
}, new RolePermission {
GroupType = GroupType.MembersOnly,
Role = UserRole.Elder,
Permissions = PermissionsElder
}, new RolePermission {
GroupType = GroupType.MembersOnly,
Role = UserRole.Leader,
Permissions = PermissionsLeader
},
new RolePermission {
GroupType = GroupType.Private,
Role = UserRole.Member,
Permissions = PermissionsMember
}, new RolePermission {
GroupType = GroupType.Private,
Role = UserRole.Elder,
Permissions = PermissionsElder
}, new RolePermission {
GroupType = GroupType.Private,
Role = UserRole.Leader,
Permissions = PermissionsLeader
}
];
public static readonly Schema.Group EMD_Dragons = new Schema.Group {
GroupID = "8e68214a-c801-4759-8461-d01f28484134",
Name = "Dragons",
@ -26,27 +102,125 @@ public class GroupController : Controller {
this.ctx = ctx;
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/CreateGroup")]
[VikingSession]
public IActionResult CreateGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupCreateRequest) {
uint gameId = ClientVersion.GetGameID(apiKey);
if (viking.GroupMemberships.Any(g => g.Group.GameID == gameId)) {
return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.CreatorIsNotApproved });
}
CreateGroupRequest request = XmlUtil.DeserializeXml<CreateGroupRequest>(groupCreateRequest);
request.Name = request.Name.Trim();
// Cue the gauntlet of validity checks.
if (request.Type <= GroupType.System) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupTypeIsInvalid });
//if (request.MaxMemberLimit < 4) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupMaxMemberLimitInvalid }); // Not actually used by the game.
if (request.Name.Length == 0) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupNameIsEmpty });
if (request.Description.Length == 0) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupDescriptionIsEmpty });
if (viking.GroupMemberships.Any(g => g.Group.Name.Equals(request.Name, StringComparison.InvariantCultureIgnoreCase))) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupNameIsDuplicate });
Model.Group group = new Model.Group {
Name = request.Name,
Description = request.Description,
Logo = request.Logo,
Color = request.Color,
Type = request.Type,
CreateDate = DateTime.Now,
GameID = gameId,
MaxMemberLimit = 50,
GroupID = Guid.NewGuid(),
Vikings = new List<GroupMember>()
};
ctx.Groups.Add(group);
group.Vikings.Add(new GroupMember {
Viking = viking,
Group = group,
UserRole = UserRole.Leader,
JoinDate = group.CreateDate
});
group.LastActiveTime = group.CreateDate;
ctx.SaveChanges();
return Ok(new CreateGroupResult {
Success = true,
Status = CreateGroupStatus.Success,
Group = new Schema.Group {
Name = group.Name,
Description = group.Description,
Logo = group.Logo,
Color = group.Color,
Type = group.Type,
OwnerID = viking.Uid.ToString(),
Points = 0,//group.Points,
Active = false,//group.Vikings.Count >= 4,
MemberLimit = group.MaxMemberLimit,
GroupID = group.GroupID.ToString()
}
// TODO: Delete after 15 days of less than 4 members.
});
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/EditGroup")]
[VikingSession]
public IActionResult EditGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupEditRequest) {
EditGroupRequest request = XmlUtil.DeserializeXml<EditGroupRequest>(groupEditRequest);
request.Name = request.Name.Trim();
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(gv => gv.Group.GroupID.ToString() == request.GroupID);
if (vikingRole == null) {
return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupNotFound });
} else if (vikingRole.UserRole < UserRole.Elder) {
return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.PermissionDenied });
}
// Cue the gauntlet of validity checks.
if (request.Type != null && request.Type <= GroupType.System) return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupTypeIsInvalid });
//if (request.MaxMemberLimit < 4) return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupMaxMemberLimitInvalid }); // Not actually used by the game.
if ((request.Name?.Length ?? 0) == 0) request.Name = vikingRole.Group.Name;
if ((request.Description?.Length ?? 0) == 0) request.Description = vikingRole.Group.Description;
if (request.Name != vikingRole.Group.Name && viking.GroupMemberships.Any(gm => gm.Group.Name.Equals(request.Name, StringComparison.InvariantCultureIgnoreCase))) return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupNameIsDuplicate });
vikingRole.Group.Name = request.Name;
vikingRole.Group.Description = request.Description;
if (request.Type != null) vikingRole.Group.Type = (GroupType)request.Type;
if ((request.Color?.Length ?? 0) > 0) vikingRole.Group.Color = request.Color;
if ((request.Logo?.Length ?? 0) > 0) vikingRole.Group.Logo = request.Logo;
ctx.SaveChanges();
return Ok(new EditGroupResult {
Success = true,
Status = EditGroupStatus.Success,
NewRolePermissions = RolePermissions
});
}
[HttpPost]
[Produces("application/xml")]
[Route("GroupWebService.asmx/JoinGroup")]
[VikingSession]
public IActionResult JoinGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupID) {
AddEMDGroups();
uint version = ClientVersion.GetVersion(apiKey);
// Only implemented for EMD so far.
if (version == ClientVersion.EMD) {
if (viking.Groups.Any(g => {
// Check for loyalty.
string id = g.GroupID.ToString();
return id == EMD_Dragons.GroupID || id == EMD_Scorpions.GroupID;
})) {
return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.ALREADY_MEMBER });
}
groupID = groupID.ToUpper();
Model.Group? group = ctx.Groups.FirstOrDefault(g => g.GroupID.ToString() == groupID);
if (group != null) {
group.Vikings.Add(viking);
public IActionResult JoinGroupV1(Viking viking, [FromForm] string apiKey, [FromForm] string groupID) {
uint gameId = ClientVersion.GetGameID(apiKey);
// Check for loyalty.
if (viking.GroupMemberships.Any(g => g.Group.GameID == gameId)) {
return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.SELF_BLOCKED });
}
Model.Group? group = ctx.Groups.FirstOrDefault(g => g.GroupID.ToString().Equals(groupID, StringComparison.OrdinalIgnoreCase));
if (group != null) {
// This check is only on this side to prevent people from attempting to circumvent the join limit.
if (group.Type <= GroupType.System || group.Vikings.Count < group.MaxMemberLimit) {
group.Vikings.Add(new GroupMember {
Viking = viking,
Group = group,
UserRole = UserRole.Member
});
ctx.SaveChanges();
return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.APPROVED });
}
@ -56,49 +230,320 @@ public class GroupController : Controller {
[HttpPost]
[Produces("application/xml")]
[Route("GroupWebService.asmx/GetGroupsByGroupType")]
[Route("V2/GroupWebService.asmx/JoinGroup")]
[VikingSession]
public IActionResult JoinGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupJoinRequest) {
uint gameId = ClientVersion.GetGameID(apiKey);
JoinGroupRequest request = XmlUtil.DeserializeXml<JoinGroupRequest>(groupJoinRequest);
Model.Group? group = ctx.Groups.FirstOrDefault(g => g.GroupID.ToString() == request.GroupID.ToUpper());
if (group == null) return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.Error });
if (group.Type >= GroupType.Private) {
return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.GroupTypeIsNotPublic });
}
GroupMember? existing = viking.GroupMemberships.FirstOrDefault(g => g.Group.GameID == gameId);
if (existing != null) {
if (existing.Group == group)
return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.UserAlreadyMemberOfTheGroup });
existing.Group.Vikings.Remove(existing);
if (!existing.Group.Vikings.Any()) ctx.Groups.Remove(existing.Group);
}
if (group.Type == GroupType.MembersOnly) {
if (!group.JoinRequests.Any(r => r.Viking == viking))
group.JoinRequests.Add(new GroupJoinRequest {
Group = group,
Viking = viking,
//Message = request.Message // For future implemention, once moderation is possible.
});
ctx.SaveChanges();
return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.JoinRequestPending });
}
if (group.Vikings.Count >= group.MaxMemberLimit)
return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.GroupIsFull });
GroupMember joinee = new GroupMember {
Viking = viking,
Group = group,
UserRole = UserRole.Member,
JoinDate = DateTime.Now
};
group.Vikings.Add(joinee);
group.LastActiveTime = joinee.JoinDate;
ctx.SaveChanges();
return Ok(new GroupJoinResult { Success = true, Status = JoinGroupStatus.Success });
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/LeaveGroup")]
[VikingSession]
public IActionResult LeaveGroup(Viking viking, [FromForm] string groupLeaveRequest) {
LeaveGroupRequest request = XmlUtil.DeserializeXml<LeaveGroupRequest>(groupLeaveRequest);
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(g => g.Group.GroupID.ToString() == request.GroupID);
if (vikingRole == null) return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.Error });
GroupMember? targetRole;
if (viking.Uid.ToString().Equals(request.UserID, StringComparison.CurrentCultureIgnoreCase)) {
targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking == viking);
} else if (vikingRole.UserRole >= UserRole.Elder) {
targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid.ToString() == request.UserID);
} else return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.Error });
if (targetRole == null)
return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.UserNotAMemberOfTheGroup });
vikingRole.Group.Vikings.Remove(targetRole);
if (!vikingRole.Group.Vikings.Any()) ctx.Groups.Remove(vikingRole.Group);
ctx.SaveChanges();
return Ok(new LeaveGroupResult { Success = true, Status = LeaveGroupStatus.Success });
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/GetGroups")]
public IActionResult GetGroups([FromForm] string apiKey, [FromForm] string getGroupsRequest) {
uint gameId = ClientVersion.GetGameID(apiKey);
GetGroupsRequest request = XmlUtil.DeserializeXml<GetGroupsRequest>(getGroupsRequest);
IEnumerable<Model.Group> groups = ctx.Groups;
if (request.ForUserID != null) {
Viking? target = ctx.Vikings.FirstOrDefault(v => request.ForUserID.ToUpper() == v.Uid.ToString());
if (target == null) return Ok(new GetGroupsResult { Success = false });
groups = target.GroupMemberships.Select(gv => gv.Group);
} else {
groups = groups.Where(g => g.Type == GroupType.Public || g.Type == GroupType.MembersOnly);
}
if (request.Name != null) {
groups = groups.Where(g => g.Name?.Contains(request.Name, StringComparison.InvariantCultureIgnoreCase) == true);
}
int skip = 0;
if (request.PageSize != null) {
if ((request.PageNo ?? 0) > 1) skip = (int)((request.PageNo! - 1) * request.PageSize);
if (skip > 0) groups = groups.Skip(skip);
groups = groups.Take((int) request.PageSize);
}
groups = groups.Where(g => g.GameID == gameId).OrderByDescending(g => g.Points);
return Ok(new GetGroupsResult {
Success = true,
Groups = groups.Select((g, i) => {
Schema.Group group = new Schema.Group {
Name = g.Name,
Description = g.Description,
GroupID = g.GroupID.ToString(),
OwnerID = (g.Vikings.FirstOrDefault(v => v.UserRole == UserRole.Leader)?.Viking?.Uid ?? Guid.Empty).ToString(),
Color = g.Color,
Logo = g.Logo,
Type = g.Type,
Rank = i+skip+1,
MemberLimit = g.MaxMemberLimit
};
if (request.IncludeMemberCount) group.TotalMemberCount = g.Vikings.Count;
return group;
}).ToArray(),
RolePermissions = RolePermissions
});
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/RemoveMember")]
[VikingSession]
public IActionResult RemoveMember(Viking viking, [FromForm] string removeMemberRequest) {
RemoveMemberRequest request = XmlUtil.DeserializeXml<RemoveMemberRequest>(removeMemberRequest);
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(g => g.Group.GroupID.ToString() == request.GroupID);
if (vikingRole == null)
return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.Error });
if (vikingRole.UserRole < UserRole.Elder)
return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.UserHasNoPermission });
GroupMember? targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid.ToString() == request.RemoveUserID);
if (targetRole == null)
return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.UserNotAMemberOfTheGroup });
vikingRole.Group.Vikings.Remove(targetRole);
if (!vikingRole.Group.Vikings.Any()) ctx.Groups.Remove(vikingRole.Group);
ctx.SaveChanges();
return Ok(new RemoveMemberResult { Success = true, Status = RemoveMemberStatus.Success });
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/AuthorizeJoinRequest")]
[VikingSession]
public IActionResult AuthorizeJoinRequest(Viking viking, [FromForm] string apiKey, [FromForm] string authorizeJoinRequest) {
uint gameId = ClientVersion.GetGameID(apiKey);
AuthorizeJoinRequest request = XmlUtil.DeserializeXml<AuthorizeJoinRequest>(authorizeJoinRequest);
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(g => g.Group.GroupID.ToString() == request.GroupID);
if (vikingRole == null)
return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.ApproverNotInThisGroup });
if (vikingRole.UserRole < UserRole.Elder)
return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.ApproverHasNoPermission });
Viking? target = ctx.Vikings.FirstOrDefault(v => v.Uid.ToString() == request.UserID);
if (target == null) {
return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.Error });
}
GroupMember? existing = target.GroupMemberships.FirstOrDefault(gm => gm.Group.GameID == gameId);
if (existing != null) {
return Ok(new AuthorizeJoinResult {
Success = false,
Status = existing.Group == vikingRole.Group
? AuthorizeJoinStatus.UserAlreadyMemberOfTheGroup
: AuthorizeJoinStatus.UserHasNoJoinRequest
});
}
if (vikingRole.Group.Vikings.Count >= vikingRole.Group.MaxMemberLimit)
return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.GroupIsFull });
if (request.Approved) {
GroupMember joinee = new GroupMember {
Viking = target,
Group = vikingRole.Group,
UserRole = UserRole.Member,
JoinDate = DateTime.Now
};
vikingRole.Group.Vikings.Add(joinee);
vikingRole.Group.LastActiveTime = joinee.JoinDate;
}
GroupJoinRequest? joinRequest = ctx.GroupJoinRequests.Find(target.Id, vikingRole.GroupID);
if (joinRequest != null) ctx.GroupJoinRequests.Remove(joinRequest);
ctx.SaveChanges();
return Ok(new AuthorizeJoinResult { Success = true, Status = AuthorizeJoinStatus.Success });
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/AssignRole")]
[VikingSession]
public IActionResult AssignRole(Viking viking, [FromForm] string assignRoleRequest) {
AssignRoleRequest request = XmlUtil.DeserializeXml<AssignRoleRequest>(assignRoleRequest);
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(g => g.Group.GroupID.ToString() == request.GroupID);
if (vikingRole == null)
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverNotMemberOfTheGroup });
if (vikingRole.UserRole < UserRole.Elder)
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
GroupMember? targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid.ToString() == request.MemberID);
if (targetRole == null)
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.MemberNotPartOfTheGroup });
if (targetRole.UserRole == request.NewRole)
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.MemberAlreadyInTheRole });
if (vikingRole.UserRole == UserRole.Leader) {
// Disallow leader from simply demoting themself.
if (viking == targetRole.Viking)
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
} else if (viking != targetRole.Viking || request.NewRole > vikingRole.UserRole) {
// Disallow Elders from promoting themselves to leader, or promoting anyone else to elder, but allow them to demote themselves.
return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
}
targetRole.UserRole = request.NewRole;
if (request.NewRole == UserRole.Leader)
vikingRole.UserRole = UserRole.Elder; // This is the only way a leader can demote themself.
ctx.SaveChanges();
return Ok(new AssignRoleResult { Success = true, Status = AssignRoleStatus.Success });
}
[HttpPost]
[Produces("application/xml")]
[Route("V2/GroupWebService.asmx/GetPendingJoinRequest")]
[VikingSession]
public IActionResult GetPendingJoinRequests(Viking viking, [FromForm] string getPendingJoinRequest) {
GetPendingJoinRequest request = XmlUtil.DeserializeXml<GetPendingJoinRequest>(getPendingJoinRequest);
GroupMember? vikingRole = viking.GroupMemberships.FirstOrDefault(g => g.Group.GroupID.ToString() == request.GroupID);
if (vikingRole?.UserRole >= UserRole.Elder) {
return Ok(new GetPendingJoinResult {
Success = true,
Requests = vikingRole.Group.JoinRequests
.Select(r => {
PendingJoinRequest req = new PendingJoinRequest {
UserID = r.Viking.Uid.ToString(),
GroupID = vikingRole.Group.GroupID.ToString(),
StatusID = GroupJoinRequestStatus.Pending,
Message = r.Message ?? "Hello! Please invite me to your Crew!" // Defualt from Math Blaster btw
};
req.FromUserID = req.UserID;
return req;
}).ToArray()
});
}
return Ok(new GetPendingJoinResult { Success = false });
}
[HttpPost]
[Produces("application/xml")]
[Route("GroupWebService.asmx/GetGroupsByUserID")]
public Schema.Group[] GetGroupsByUserID([FromForm] string apiKey, [FromForm] string userId) {
uint gameId = ClientVersion.GetGameID(apiKey);
Viking? viking = ctx.Vikings.FirstOrDefault(v => v.Uid.ToString() == userId);
if (viking == null) return [];
return viking.GroupMemberships.Where(gm => gm.Group.GameID == gameId).Select(gm => new Schema.Group {
GroupID = gm.Group.GroupID.ToString(),
Name = gm.Group.Name,
Color = gm.Group.Color,
Logo = gm.Group.Logo,
MemberLimit = gm.Group.MaxMemberLimit
}).ToArray();
}
[HttpPost]
[Produces("application/xml")]
[Route("GroupWebService.asmx/GetGroupsByGroupType")]
public Schema.Group[] GetGroupsByGroupType([FromForm] string apiKey, [FromForm] string groupType) {
AddEMDGroups();
uint gameId = ClientVersion.GetGameID(apiKey);
List<Schema.Group> groups = new List<Schema.Group>();
foreach (Model.Group group in ctx.Groups) {
if (group.ApiKey == apiKey && group.Type.ToString() == groupType) groups.Add(new Schema.Group {
if (group.GameID == gameId && group.Type.ToString() == groupType) groups.Add(new Schema.Group {
GroupID = group.GroupID.ToString(),
Name = group.Name,
Color = group.Color,
Logo = group.Logo,
Type = group.Type
Type = group.Type,
MemberLimit = group.MaxMemberLimit
});
}
return groups.ToArray();
}
private void AddEMDGroups() {
bool changed = false;
Guid DragonString = new Guid(EMD_Dragons.GroupID);
Guid ScorpionString = new Guid(EMD_Scorpions.GroupID);
if (!ctx.Groups.Any(g => g.GroupID == DragonString)) {
ctx.Groups.Add(new Model.Group {
GroupID = DragonString,
Name = EMD_Dragons.Name,
Color = EMD_Dragons.Color,
Logo = EMD_Dragons.Logo,
Type = GroupType.System,
ApiKey = "dd602cf1-cc98-4738-9a0a-56dde3026947"
});
changed = true;
}
if (!ctx.Groups.Any(g => g.GroupID == ScorpionString)) {
ctx.Groups.Add(new Model.Group {
GroupID = ScorpionString,
Name = EMD_Scorpions.Name,
Color = EMD_Scorpions.Color,
Logo = EMD_Scorpions.Logo,
Type = GroupType.System,
ApiKey = "dd602cf1-cc98-4738-9a0a-56dde3026947"
});
changed = true;
}
if (changed) ctx.SaveChanges();
[HttpPost]
[Produces("application/xml")]
[Route("GroupWebService.asmx/GetMembersByGroupID")]
public Schema.GroupMember[] GetMembersByGroupID([FromForm] string groupID) {
groupID = groupID.ToUpper();
Model.Group? group = ctx.Groups.FirstOrDefault(
g => g.GroupID.ToString() == groupID
);
if (group == null) return [];
return group.Vikings.Select(v => new Schema.GroupMember {
DisplayName = group.GameID == ClientVersion.MB && v.Viking.AvatarSerialized != null
? XmlUtil.DeserializeXml<AvatarData>(v.Viking.AvatarSerialized).DisplayName
: v.Viking.Name,
UserID = v.Viking.Uid.ToString(),
JoinDate = v.JoinDate,
RoleID = (int) v.UserRole,
Online = false, // There's no way to check this.
Rank = 0,
GroupID = group.GroupID.ToString(),
Points = group.Points
}).ToArray();
}
}

View File

@ -7,6 +7,7 @@ using sodoff.Schema;
using sodoff.Services;
using sodoff.Util;
using sodoff.Configuration;
using GroupMember = sodoff.Model.GroupMember;
namespace sodoff.Controllers.Common;
public class ProfileController : Controller {
@ -152,18 +153,18 @@ public class ProfileController : Controller {
UserGameCurrency currency = achievementService.GetUserCurrency(viking);
ICollection<Model.Group> groups = viking.Groups;
ICollection<GroupMember> groups = viking.GroupMemberships;
UserProfileGroupData[] groupData = new UserProfileGroupData[groups.Count];
int i = 0;
foreach (Model.Group group in groups) {
foreach (GroupMember role in groups) {
groupData[i] = new UserProfileGroupData {
GroupID = group.GroupID.ToString(),
Name = group.Name,
Color = group.Color,
Logo = group.Logo,
TypeID = (int)group.Type,
RoleID = 0
GroupID = role.Group.GroupID.ToString(),
Name = role.Group.Name,
Color = role.Group.Color,
Logo = role.Group.Logo,
TypeID = (int)role.Group.Type,
RoleID = role.UserRole
};
i++;
}

View File

@ -1,6 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using sodoff.Configuration;
using System.Text.Json;
namespace sodoff.Model;
public class DBContext : DbContext {
@ -29,6 +30,8 @@ public class DBContext : DbContext {
public DbSet<Neighborhood> Neighborhoods { get; set; } = null!;
// we had a brief debate on whether it's neighborhoods or neighborheed
public DbSet<Group> Groups { get; set; } = null!;
public DbSet<GroupMember> GroupMembers { get; set; } = null!;
public DbSet<GroupJoinRequest> GroupJoinRequests { get; set; } = null!;
public DbSet<Rating> Ratings { get; set; } = null!;
public DbSet<RatingRank> RatingRanks { get; set; } = null!;
public DbSet<UserMissionData> UserMissionData { get; set; } = null!;
@ -69,6 +72,9 @@ public class DBContext : DbContext {
}
protected override void OnModelCreating(ModelBuilder builder) {
builder.Entity<GroupMember>().HasKey(["VikingID", "GroupID"]);
builder.Entity<GroupJoinRequest>().HasKey(["VikingID", "GroupID"]);
// Sessions
builder.Entity<Session>().HasOne(s => s.User)
.WithMany(e => e.Sessions)
@ -147,8 +153,8 @@ public class DBContext : DbContext {
builder.Entity<Viking>().HasOne(v => v.Neighborhood)
.WithOne(e => e.Viking);
builder.Entity<Viking>().HasMany(v => v.Groups)
.WithMany(e => e.Vikings);
builder.Entity<Viking>().HasMany(v => v.GroupMemberships)
.WithOne(g => g.Viking);
builder.Entity<Viking>().HasMany(v => v.Ratings)
.WithOne(r => r.Viking);
@ -282,7 +288,15 @@ public class DBContext : DbContext {
// Groups
builder.Entity<Group>().HasMany(r => r.Vikings)
.WithMany(e => e.Groups);
.WithOne(v => v.Group);
builder.Entity<GroupMember>().HasOne(r => r.Group)
.WithMany(g => g.Vikings);
builder.Entity<GroupMember>().HasOne(r => r.Viking)
.WithMany(g => g.GroupMemberships);
builder.Entity<Group>().HasMany(r => r.JoinRequests)
.WithOne(r => r.Group);
builder.Entity<GroupJoinRequest>().HasOne(r => r.Group)
.WithMany(g => g.JoinRequests);
// Rating
builder.Entity<Rating>().HasOne(r => r.Viking)

View File

@ -3,23 +3,33 @@ using System.ComponentModel.DataAnnotations;
namespace sodoff.Model;
// Implementation for EMD, add whatever else if needed
public class Group {
[Key]
public int Id { get; set; }
[Required]
public Guid GroupID { get; set; }
public string Name { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public GroupType Type { get; set; }
public string Color { get; set; }
public string? Logo { get; set; }
public string Logo { get; set; }
public string? Color { get; set; }
public string ApiKey { get; set; }
public int Points { get; set; }
public virtual ICollection<Viking> Vikings { get; set; } = null!;
public DateTime CreateDate { get; set; }
public DateTime? LastActiveTime { get; set; }
public uint GameID { get; set; }
public int MaxMemberLimit { get; set; }
public virtual ICollection<GroupMember> Vikings { get; set; } = null!;
public virtual ICollection<GroupJoinRequest> JoinRequests { get; set; } = null!;
}

View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace sodoff.Model;
public class GroupJoinRequest {
[Key]
public int VikingID { get; set; }
[Key]
public int GroupID { get; set; }
public string? Message { get; set; }
public virtual Viking Viking { get; set; } = null!;
public virtual Group Group { get; set; } = null!;
}

16
src/Model/GroupMember.cs Normal file
View File

@ -0,0 +1,16 @@
using sodoff.Schema;
using System.ComponentModel.DataAnnotations;
namespace sodoff.Model;
public class GroupMember {
[Key]
public int VikingID { get; set; }
[Key]
public int GroupID { get; set; }
public UserRole UserRole { get; set; }
public DateTime JoinDate { get; set; }
public virtual Viking Viking { get; set; } = null!;
public virtual Group Group { get; set; } = null!;
}

View File

@ -47,7 +47,7 @@ public class Viking {
public virtual ICollection<MMORole> MMORoles { get; set; } = null!;
public virtual Neighborhood? Neighborhood { get; set; } = null!;
[JsonIgnore]
public virtual ICollection<Group> Groups { get; set; } = null!;
public virtual ICollection<GroupMember> GroupMemberships { get; set; } = null!;
public virtual ICollection<Rating> Ratings { get; set; } = null!;
public virtual Dragon? SelectedDragon { get; set; }
public virtual ICollection<UserMissionData> UserMissions { get; set; } = null!;

View File

@ -0,0 +1,25 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "AssignRoleRequest", IsNullable = true)]
[Serializable]
public class AssignRoleRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "MemberID")]
public string MemberID;
[XmlElement(ElementName = "NewRole")]
public UserRole NewRole;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "AssignRoleResult", IsNullable = true)]
[Serializable]
public class AssignRoleResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "InitiatorNewRole", IsNullable = true)]
public UserRole? InitiatorNewRole;
[XmlElement(ElementName = "Status")]
public AssignRoleStatus Status;
}

View File

@ -0,0 +1,18 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum AssignRoleStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
ApproverNotMemberOfTheGroup,
[XmlEnum("4")]
ApproverHasNoPermission,
[XmlEnum("5")]
MemberAlreadyInTheRole,
[XmlEnum("6")]
MemberNotPartOfTheGroup
}

View File

@ -0,0 +1,25 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "AuthorizeJoinRequest", IsNullable = true)]
[Serializable]
public class AuthorizeJoinRequest {
[XmlElement(ElementName = "Approved")]
public bool Approved;
[XmlElement(ElementName = "JoineeID")]
public string JoineeID;
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
}

View File

@ -0,0 +1,13 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "AuthorizeJoinResult", IsNullable = true)]
[Serializable]
public class AuthorizeJoinResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Status")]
public AuthorizeJoinStatus Status;
}

View File

@ -0,0 +1,24 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum AuthorizeJoinStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
GroupIsFull,
[XmlEnum("4")]
GroupTypeIsNotPublic,
[XmlEnum("5")]
UserAlreadyMemberOfTheGroup,
[XmlEnum("6")]
GroupTypeIsPublic,
[XmlEnum("7")]
ApproverNotInThisGroup,
[XmlEnum("8")]
ApproverHasNoPermission,
[XmlEnum("9")]
UserHasNoJoinRequest
}

View File

@ -0,0 +1,40 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "CreateGroupRequest", IsNullable = true)]
[Serializable]
public class CreateGroupRequest {
[XmlElement(ElementName = "Name")]
public string Name;
[XmlElement(ElementName = "Description")]
public string Description;
[XmlElement(ElementName = "Type")]
public GroupType Type;
[XmlElement(ElementName = "Logo")]
public string Logo;
[XmlElement(ElementName = "Color")]
public string Color;
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "DefaultLeaderID")]
public string DefaultLeaderID;
[XmlElement(ElementName = "ParentGroupID")]
public string ParentGroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
[XmlElement(ElementName = "MaxMemberLimit")]
public int? MaxMemberLimit;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "CreateGroupResult", IsNullable = true)]
[Serializable]
public class CreateGroupResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Status")]
public CreateGroupStatus Status;
[XmlElement(ElementName = "Group")]
public Group Group;
}

View File

@ -0,0 +1,32 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum CreateGroupStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
GroupNameInvalid,
[XmlEnum("4")]
GroupDescriptionInvalid,
[XmlEnum("5")]
GroupNameIsDuplicate,
[XmlEnum("6")]
GroupOwnerHasInSufficientCurrency,
[XmlEnum("7")]
UnableToGetCreatorDetails,
[XmlEnum("8")]
CreatorIsNotApproved,
[XmlEnum("9")]
GroupNameIsEmpty,
[XmlEnum("10")]
GroupDescriptionIsEmpty,
[XmlEnum("11")]
GroupTypeIsInvalid,
[XmlEnum("12")]
GroupMaxMemberLimitInvalid,
[XmlEnum("13")]
AutomaticItemPurchaseFailed
}

View File

@ -0,0 +1,37 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "EditGroupRequest", IsNullable = true)]
[Serializable]
public class EditGroupRequest {
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "Name")]
public string Name;
[XmlElement(ElementName = "Description")]
public string Description;
[XmlElement(ElementName = "Type")]
public GroupType? Type;
[XmlElement(ElementName = "Logo")]
public string Logo;
[XmlElement(ElementName = "Color")]
public string Color;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
[XmlElement(ElementName = "MaxMemberLimit")]
public int? MaxMemberLimit;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "EditGroupResult", IsNullable = true)]
[Serializable]
public class EditGroupResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Status")]
public EditGroupStatus Status;
[XmlElement(ElementName = "NewRolePermissions", IsNullable = true)]
public List<RolePermission> NewRolePermissions;
}

View File

@ -0,0 +1,28 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum EditGroupStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
UnableToGetUserDetails,
[XmlEnum("4")]
GroupNameInvalid,
[XmlEnum("5")]
GroupDescriptionInvalid,
[XmlEnum("6")]
GroupNameIsDuplicate,
[XmlEnum("7")]
GroupTypeIsInvalid,
[XmlEnum("8")]
PermissionDenied,
[XmlEnum("9")]
GroupNotFound,
[XmlEnum("10")]
GroupMaxMemberLimitInvalid,
[XmlEnum("11")]
GroupOwnerHasInSufficientCurrency
}

View File

@ -0,0 +1,40 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GetGroupsRequest", IsNullable = true)]
[Serializable]
public class GetGroupsRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "ForUserID")]
public string ForUserID;
[XmlElement(ElementName = "GroupID")]
public Guid? GroupID;
[XmlElement(ElementName = "Name")]
public string Name;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "IncludeMemberCount")]
public bool IncludeMemberCount;
[XmlElement(ElementName = "IncludeMinFields")]
public bool IncludeMinFields;
[XmlElement(ElementName = "PageNo")]
public int? PageNo;
[XmlElement(ElementName = "PageSize")]
public int? PageSize;
[XmlElement(ElementName = "GroupsFilter")]
public GroupsFilter GroupsFilter;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GetGroupsResult", IsNullable = true)]
[Serializable]
public class GetGroupsResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Groups")]
public Group[] Groups;
[XmlElement(ElementName = "RolePermissions", IsNullable = true)]
public List<RolePermission> RolePermissions;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GetPendingJoinRequest", IsNullable = true)]
[Serializable]
public class GetPendingJoinRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
}

View File

@ -0,0 +1,14 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GetPendingJoinResult", IsNullable = true)]
[Serializable]
public class GetPendingJoinResult {
// Token: 0x04000A48 RID: 2632
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Requests")]
public PendingJoinRequest[] Requests;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum GroupJoinRequestStatus {
[XmlEnum("1")]
Pending = 1,
[XmlEnum("2")]
Approved,
[XmlEnum("3")]
Rejected,
[XmlEnum("4")]
Cancelled,
[XmlEnum("5")]
PendingAccountOwnerRequest
}

View File

@ -0,0 +1,15 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GroupJoinResult", IsNullable = true)]
[Serializable]
public class GroupJoinResult {
// Token: 0x040009C3 RID: 2499
[XmlElement(ElementName = "Success")]
public bool Success;
// Token: 0x040009C4 RID: 2500
[XmlElement(ElementName = "Status")]
public JoinGroupStatus Status;
}

35
src/Schema/GroupMember.cs Normal file
View File

@ -0,0 +1,35 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GroupMember", IsNullable = true)]
[Serializable]
public class GroupMember {
[XmlElement(ElementName = "UserID", IsNullable = false)]
public string UserID;
[XmlElement(ElementName = "GroupID", IsNullable = false)]
public string GroupID;
[XmlElement(ElementName = "DisplayName", IsNullable = false)]
public string DisplayName;
[XmlElement(ElementName = "JoinDate")]
public DateTime JoinDate;
[XmlElement(ElementName = "Online")]
public bool Online;
[XmlElement(ElementName = "RoleID", IsNullable = true)]
public int? RoleID;
[XmlElement(ElementName = "Points", IsNullable = true)]
public int? Points;
[XmlElement(ElementName = "Rank", IsNullable = true)]
public int? Rank;
[XmlElement(ElementName = "RankTrend", IsNullable = true)]
public int? RankTrend;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "GroupsFilter", IsNullable = true)]
[Serializable]
public class GroupsFilter {
[XmlElement(ElementName = "GroupType")]
public GroupType? GroupType;
[XmlElement(ElementName = "Locale")]
public string Locale;
[XmlElement(ElementName = "PointTypeID")]
public int? PointTypeID;
}

View File

@ -0,0 +1,31 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "JoinGroupRequest", IsNullable = true)]
[Serializable]
public class JoinGroupRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
[XmlElement(ElementName = "Message")]
public string Message;
[XmlElement(ElementName = "JoinRequestStatus")]
public GroupJoinRequestStatus? JoinRequestStatus;
[XmlElement(ElementName = "JoinByInvite")]
public bool JoinByInvite;
[XmlElement(ElementName = "InviterID")]
public string InviterID;
}

View File

@ -0,0 +1,28 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum JoinGroupStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
GroupIsFull,
[XmlEnum("4")]
GroupTypeIsNotPublic,
[XmlEnum("5")]
UserAlreadyMemberOfTheGroup,
[XmlEnum("6")]
GroupTypeIsPublic,
[XmlEnum("7")]
MessageInvalid,
[XmlEnum("8")]
JoinRequestPending,
[XmlEnum("9")]
InviteNeededToJoin,
[XmlEnum("10")]
NoValidInvite,
[XmlEnum("11")]
InviterHasNoPermission
}

View File

@ -0,0 +1,19 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "LeaveGroupRequest", IsNullable = true)]
[Serializable]
public class LeaveGroupRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
}

View File

@ -0,0 +1,13 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "LeaveGroupResult", IsNullable = true)]
[Serializable]
public class LeaveGroupResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Status")]
public LeaveGroupStatus Status;
}

View File

@ -0,0 +1,12 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum LeaveGroupStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
UserNotAMemberOfTheGroup
}

View File

@ -0,0 +1,22 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "PendingJoinRequest", IsNullable = true)]
[Serializable]
public class PendingJoinRequest {
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "FromUserID")]
public string FromUserID;
[XmlElement(ElementName = "Message")]
public string Message;
[XmlElement(ElementName = "StatusID", IsNullable = true)]
public GroupJoinRequestStatus? StatusID;
}

View File

@ -0,0 +1,22 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "RemoveMemberRequest", IsNullable = true)]
[Serializable]
public class RemoveMemberRequest {
[XmlElement(ElementName = "RemoveUserID")]
public string RemoveUserID;
[XmlElement(ElementName = "UserID")]
public string UserID;
[XmlElement(ElementName = "GroupID")]
public string GroupID;
[XmlElement(ElementName = "ProductGroupID")]
public int? ProductGroupID;
[XmlElement(ElementName = "ProductID")]
public int? ProductID;
}

View File

@ -0,0 +1,13 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "RemoveMemberResult", IsNullable = true)]
[Serializable]
public class RemoveMemberResult {
[XmlElement(ElementName = "Success")]
public bool Success;
[XmlElement(ElementName = "Status")]
public RemoveMemberStatus Status;
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum RemoveMemberStatus {
[XmlEnum("1")]
Success = 1,
[XmlEnum("2")]
Error,
[XmlEnum("3")]
UserNotAMemberOfTheGroup,
[XmlEnum("4")]
UserHasNoPermission,
[XmlEnum("5")]
InvalidParameters
}

View File

@ -0,0 +1,16 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
[XmlRoot(ElementName = "RP", IsNullable = true)]
[Serializable]
public class RolePermission {
[XmlElement(ElementName = "G")]
public GroupType GroupType;
[XmlElement(ElementName = "R")]
public UserRole Role;
[XmlElement(ElementName = "P")]
public List<string> Permissions;
}

View File

@ -9,7 +9,7 @@ public class UserProfileGroupData
public string GroupID;
[XmlElement(ElementName = "RoleID", IsNullable = true)]
public int? RoleID;
public UserRole? RoleID;
[XmlElement(ElementName = "TypeID", IsNullable = true)]
public int? TypeID;

12
src/Schema/UserRole.cs Normal file
View File

@ -0,0 +1,12 @@
using System.Xml.Serialization;
namespace sodoff.Schema;
public enum UserRole {
[XmlEnum("1")]
Member = 1,
[XmlEnum("2")]
Elder,
[XmlEnum("3")]
Leader
}