From 01a08e775f87c73bf21f4f658111d7a9b715d647 Mon Sep 17 00:00:00 2001 From: Collin <53619305+Cowplant-Simmer-Collin@users.noreply.github.com> Date: Mon, 19 Aug 2019 02:15:22 +0200 Subject: [PATCH] [API] Added funtionality and efficiency (#153) * [API] Added funtionality and efficiency - userOauth token (with specified permissions) - avatarinfo get avatars from specific user (req user auth) get avatars from multiple ids get all avatars now can get up to 500 avatars per page getting all neighborhood avatars is more efficient online avatars can also be requested as compact now (only online count) - lotinfo json objects now include lot_id (more consistent/reliable value than location) json objects now include admit_mode get lots from multiple ids online lots can also be requested as compact now (only online count) added funtion for getting all the lots by pages, and max 500 lots per page * [API] userApiFixes - compact now works more efficient - stress sql bandwidth fixed on getAllAvatars and GetAllLots --- .../Controllers/AvatarInfoController.cs | 165 ++++++++++++---- .../Controllers/LotInfoController.cs | 185 +++++++++++++++--- .../Controllers/UserOAuthController.cs | 128 ++++++++++++ .../DA/AvatarClaims/IAvatarClaims.cs | 1 + .../DA/AvatarClaims/SqlAvatarClaims.cs | 4 + .../DA/Avatars/IAvatars.cs | 6 +- .../DA/Avatars/SqlAvatars.cs | 22 +++ .../DA/LotClaims/DbLotClaim.cs | 1 + .../FSO.Server.Database/DA/Lots/ILots.cs | 3 + .../FSO.Server.Database/DA/Lots/SqlLots.cs | 23 ++- 10 files changed, 467 insertions(+), 71 deletions(-) create mode 100644 TSOClient/FSO.Server.Api.Core/Controllers/UserOAuthController.cs diff --git a/TSOClient/FSO.Server.Api.Core/Controllers/AvatarInfoController.cs b/TSOClient/FSO.Server.Api.Core/Controllers/AvatarInfoController.cs index e88654f60..933127944 100644 --- a/TSOClient/FSO.Server.Api.Core/Controllers/AvatarInfoController.cs +++ b/TSOClient/FSO.Server.Api.Core/Controllers/AvatarInfoController.cs @@ -16,6 +16,37 @@ namespace FSO.Server.Api.Core.Controllers [ApiController] public class AvatarInfoController : ControllerBase { + //get the avatars by user_id + [Route("userapi/user/avatars")] + public IActionResult GetByUser() + { + var api = Api.INSTANCE; + var user = api.RequireAuthentication(Request); + if (!user.Claims.Contains("userReadPermissions")) return ApiResponse.Json(HttpStatusCode.OK, new JSONAvatarError("No read premissions found.")); + + using (var da = api.DAFactory.Get()) + { + var avatars = da.Avatars.GetByUserId(user.UserID); + List avatarJson = new List(); + foreach (var avatar in avatars) + { + avatarJson.Add(new JSONAvatar + { + avatar_id = avatar.avatar_id, + shard_id = avatar.shard_id, + name = avatar.name, + gender = avatar.gender, + date = avatar.date, + description = avatar.description, + current_job = avatar.current_job, + mayor_nhood = avatar.mayor_nhood + }); + } + var avatarsJson = new JSONAvatars(); + avatarsJson.avatars = avatarJson; + return ApiResponse.Json(HttpStatusCode.OK, avatarsJson); + } + } //get the avatar by id [HttpGet] [Route("userapi/avatars/{avartarId}")] @@ -44,22 +75,60 @@ public IActionResult GetByID(uint avartarId) return ApiResponse.Json(HttpStatusCode.OK, avatarJson); } } + //get the avatars by ids + [Route("userapi/avatars")] + public IActionResult GetByIDs([FromQuery(Name = "ids")]string idsString) + { + var api = Api.INSTANCE; + try + { + uint[] ids = Array.ConvertAll(idsString.Split(","), uint.Parse); + using (var da = api.DAFactory.Get()) + { + var avatars = da.Avatars.GetMultiple(ids); + List avatarJson = new List(); + foreach (var avatar in avatars) + { + avatarJson.Add(new JSONAvatar + { + avatar_id = avatar.avatar_id, + shard_id = avatar.shard_id, + name = avatar.name, + gender = avatar.gender, + date = avatar.date, + description = avatar.description, + current_job = avatar.current_job, + mayor_nhood = avatar.mayor_nhood + }); + } + var avatarsJson = new JSONAvatars(); + avatarsJson.avatars = avatarJson; + return ApiResponse.Json(HttpStatusCode.OK, avatarsJson); + } + } + catch + { + return ApiResponse.Json(HttpStatusCode.NotFound, new JSONAvatarError("Error during cast. (invalid_value)")); + } + } //gets all the avatars from one city [HttpGet] [Route("userapi/city/{shardId}/avatars/page/{pageNum}")] - public IActionResult GetAll(int shardId,int pageNum) + public IActionResult GetAll(int shardId,int pageNum, [FromQuery(Name = "avatars_on_page")]int perPage) { var api = Api.INSTANCE; - + if(perPage == 0) + { + perPage = 100; + } + if (perPage > 500) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("The max amount of avatars per page is 500")); using (var da = api.DAFactory.Get()) { pageNum = pageNum - 1; - var avatars = da.Avatars.All(shardId); - var avatarCount = avatars.Count(); - var totalPages = (avatars.Count() - 1)/100 + 1; - avatars = avatars.Skip(pageNum * 100); - avatars = avatars.Take(100); + var avatars = da.Avatars.AllByPage(shardId, pageNum * perPage, perPage,"avatar_id"); + var avatarCount = avatars.Total; + var totalPages = (avatars.Total - 1)/perPage + 1; var pageAvatarsJson = new JSONAvatarsPage(); pageAvatarsJson.total_avatars = avatarCount; @@ -135,22 +204,26 @@ public IActionResult GetByNhood(int shardId, uint nhoodId) List avatarJson = new List(); foreach (var lot in lots) { - var roomies = da.Roommates.GetLotRoommates(lot.lot_id).Where(x => x.is_pending == 0).Select(x => x.avatar_id); - foreach (var roomie in roomies) + if(lot.category != FSO.Common.Enum.LotCategory.community) { - var roomieAvatar = da.Avatars.Get(roomie); - avatarJson.Add(new JSONAvatar + var roomies = da.Roommates.GetLotRoommates(lot.lot_id).Where(x => x.is_pending == 0).Select(x => x.avatar_id); + var avatars = da.Avatars.GetMultiple(roomies.ToArray()); + foreach (var avatar in avatars) { - avatar_id = roomieAvatar.avatar_id, - shard_id = roomieAvatar.shard_id, - name = roomieAvatar.name, - gender = roomieAvatar.gender, - date = roomieAvatar.date, - description = roomieAvatar.description, - current_job = roomieAvatar.current_job, - mayor_nhood = roomieAvatar.mayor_nhood - }); + avatarJson.Add(new JSONAvatar + { + avatar_id = avatar.avatar_id, + shard_id = avatar.shard_id, + name = avatar.name, + gender = avatar.gender, + date = avatar.date, + description = avatar.description, + current_job = avatar.current_job, + mayor_nhood = avatar.mayor_nhood + }); + } } + } var avatarsJson = new JSONAvatars(); avatarsJson.avatars = avatarJson; @@ -160,36 +233,46 @@ public IActionResult GetByNhood(int shardId, uint nhoodId) //get all online Avatars [HttpGet] [Route("userapi/avatars/online")] - public IActionResult GetOnline() + public IActionResult GetOnline([FromQuery(Name = "compact")]bool compact) { var api = Api.INSTANCE; using (var da = api.DAFactory.Get()) { - var avatarStatus = da.AvatarClaims.GetAllActiveAvatars(); - if (avatarStatus == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONAvatarError("Avatars not found")); - - List avatarSmallJson = new List(); - - foreach (var avatar in avatarStatus) + var avatarJson = new JSONAvatarOnline(); + if (compact) { - uint location = 0; - if (avatar.privacy_mode == 0) - { - location = avatar.location; - } - avatarSmallJson.Add(new JSONAvatarSmall + var avatarStatus = da.AvatarClaims.GetAllActiveAvatarsCount(); + if (avatarStatus == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONAvatarError("ammount not found")); + avatarJson.avatars_online_count = avatarStatus; + } + + + if (!compact) + { + var avatarStatus = da.AvatarClaims.GetAllActiveAvatars(); + if (avatarStatus == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONAvatarError("Avatars not found")); + + foreach (var avatar in avatarStatus) { - avatar_id = avatar.avatar_id, - name = avatar.name, - privacy_mode = avatar.privacy_mode, - location = location - }); + uint location = 0; + if (avatar.privacy_mode == 0) + { + location = avatar.location; + } + avatarSmallJson.Add(new JSONAvatarSmall + { + avatar_id = avatar.avatar_id, + name = avatar.name, + privacy_mode = avatar.privacy_mode, + location = location + }); + } + avatarJson.avatars_online_count = avatarStatus.Count(); } - var avatarJson = new JSONAvatarOnline(); - avatarJson.avatars_online_count = avatarStatus.Count(); + avatarJson.avatars = avatarSmallJson; return ApiResponse.Json(HttpStatusCode.OK, avatarJson); } @@ -213,7 +296,7 @@ public class JSONAvatarsPage } public class JSONAvatarOnline { - public int avatars_online_count { get; set; } + public int? avatars_online_count { get; set; } public List avatars { get; set; } } public class JSONAvatarSmall diff --git a/TSOClient/FSO.Server.Api.Core/Controllers/LotInfoController.cs b/TSOClient/FSO.Server.Api.Core/Controllers/LotInfoController.cs index 8564a5b40..2490746c4 100644 --- a/TSOClient/FSO.Server.Api.Core/Controllers/LotInfoController.cs +++ b/TSOClient/FSO.Server.Api.Core/Controllers/LotInfoController.cs @@ -14,6 +14,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Cors; +using FSO.Server.Database.DA.LotClaims; namespace FSO.Server.Api.Core.Controllers { @@ -156,7 +157,6 @@ public IActionResult GetByID(int lotId) { var lot = da.Lots.Get(lotId); if (lot == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lot not found")); - var roomies = da.Roommates.GetLotRoommates(lot.lot_id).Where(x => x.is_pending == 0).Select(x => x.avatar_id).ToArray(); var lotJson = new JSONLot @@ -171,12 +171,103 @@ public IActionResult GetByID(int lotId) owner_id = lot.owner_id, shard_id = lot.shard_id, skill_mode = lot.skill_mode, - roommates = roomies + roommates = roomies, + lot_id = lot.lot_id }; return ApiResponse.Json(HttpStatusCode.OK, lotJson); } } + //get the lots by ids + [Route("userapi/lots")] + public IActionResult GetByIDs([FromQuery(Name = "ids")]string idsString) + { + var api = Api.INSTANCE; + try + { + int[] ids = Array.ConvertAll(idsString.Split(","), int.Parse); + using (var da = api.DAFactory.Get()) + { + var lots = da.Lots.GetMultiple(ids); + if (lots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lot not found")); + + List lotJson = new List(); + foreach (var lot in lots) + { + var roomies = da.Roommates.GetLotRoommates(lot.lot_id).Where(x => x.is_pending == 0).Select(x => x.avatar_id).ToArray(); + lotJson.Add(new JSONLot + { + admit_mode = lot.admit_mode, + category = lot.category, + created_date = lot.created_date, + description = lot.description, + location = lot.location, + name = lot.name, + neighborhood_id = lot.neighborhood_id, + owner_id = lot.owner_id, + shard_id = lot.shard_id, + skill_mode = lot.skill_mode, + roommates = roomies, + lot_id = lot.lot_id + }); + } + var lotsJson = new JSONLots(); + lotsJson.lots = lotJson; + return ApiResponse.Json(HttpStatusCode.OK, lotsJson); + } + } + catch + { + return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Error during cast. (invalid_value)")); + } + } + //gets all the lots from one city + [HttpGet] + [Route("userapi/city/{shardId}/lots/page/{pageNum}")] + public IActionResult GetAll(int shardId, int pageNum, [FromQuery(Name = "lots_on_page")]int perPage) + { + var api = Api.INSTANCE; + if (perPage == 0) + { + perPage = 100; + } + if (perPage > 500) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("The max amount of lots per page is 500")); + using (var da = api.DAFactory.Get()) + { + pageNum = pageNum - 1; + + var lots = da.Lots.AllByPage(shardId, pageNum * perPage, perPage,"lot_id"); + var lotCount = lots.Total; + var totalPages = (lots.Total - 1) / perPage + 1; + + var pageLotsJson = new JSONLotsPage(); + pageLotsJson.total_lots = lotCount; + pageLotsJson.page = pageNum + 1; + pageLotsJson.total_pages = (int)totalPages; + pageLotsJson.lots_on_page = lots.Count(); + + if (pageNum < 0 || pageNum >= (int)totalPages) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Page not found")); + if (lots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lots not found")); + + List lotJson = new List(); + foreach (var lot in lots) + { + lotJson.Add(new JSONLotSmall + { + location = lot.location, + name = lot.name, + description = lot.description, + category = lot.category, + admit_mode = lot.admit_mode, + neighborhood_id = lot.neighborhood_id, + lot_id = lot.lot_id + }); + } + + pageLotsJson.lots = lotJson; + return ApiResponse.Json(HttpStatusCode.OK, pageLotsJson); + } + } //get lot information by location [HttpGet] [Route("userapi/city/{shardId}/lots/location/{locationId}")] @@ -203,7 +294,8 @@ public IActionResult GetByLocation(int shardId, uint locationId) owner_id = lot.owner_id, shard_id = lot.shard_id, skill_mode = lot.skill_mode, - roommates = roomies + roommates = roomies, + lot_id = lot.lot_id }; return ApiResponse.Json(HttpStatusCode.OK, LotJSON); @@ -229,10 +321,12 @@ public IActionResult GetByNhood(int shardId, uint nhoodId) name = lot.name, description = lot.description, category = lot.category, - neighborhood_id = lot.neighborhood_id + admit_mode = lot.admit_mode, + neighborhood_id = lot.neighborhood_id, + lot_id = lot.lot_id }); } - var lotsJson = new JSONLots(); + var lotsJson = new JSONLotsSmall(); lotsJson.lots = lotJson; return ApiResponse.Json(HttpStatusCode.OK, lotsJson); } @@ -253,6 +347,7 @@ public IActionResult GetByName(int shardId, string lotName) var lotJson = new JSONLot { + lot_id = lot.lot_id, admit_mode = lot.admit_mode, category = lot.category, created_date = lot.created_date, @@ -272,34 +367,52 @@ public IActionResult GetByName(int shardId, string lotName) //get online lots [HttpGet] [Route("userapi/city/{shardId}/lots/online")] - public IActionResult GetOnline(int shardId) + public IActionResult GetOnline(int shardId, [FromQuery(Name = "compact")]bool compact) { var api = Api.INSTANCE; using (var da = api.DAFactory.Get()) { - var activeLots = da.LotClaims.AllActiveLots(shardId); - if (activeLots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lots not found")); - List lotSmallJson = new List(); - var totalAvatars = 0; - foreach (var lot in activeLots) + var lotsOnlineJson = new JSONLotsOnline(); + + if (!compact) { - - lotSmallJson.Add(new JSONLotSmall + var activeLots = da.LotClaims.AllActiveLots(shardId); + if (activeLots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lots not found")); + var totalAvatars = 0; + foreach (var lot in activeLots) { - location = lot.location, - name = lot.name, - description = lot.description, - category = lot.category, - neighborhood_id = lot.neighborhood_id, - avatars_in_lot = lot.active - }); - totalAvatars += lot.active; + lotSmallJson.Add(new JSONLotSmall + { + location = lot.location, + name = lot.name, + description = lot.description, + category = lot.category, + admit_mode = lot.admit_mode, + neighborhood_id = lot.neighborhood_id, + avatars_in_lot = lot.active, + lot_id = lot.lot_id + }); + totalAvatars += lot.active; + } + lotsOnlineJson.total_lots_online = activeLots.Count(); + lotsOnlineJson.total_avatars_in_lots_online = totalAvatars; } - var lotsOnlineJson = new JSONLotsOnline(); - lotsOnlineJson.total_lots_online = activeLots.Count(); - lotsOnlineJson.total_avatars_in_lots_online = totalAvatars; + else + { + var activeLots = da.LotClaims.AllLocations(shardId); + if (activeLots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Lots not found")); + var totalAvatars = 0; + foreach (var lot in activeLots) + { + totalAvatars += lot.active; + } + + lotsOnlineJson.total_lots_online = activeLots.Count(); + lotsOnlineJson.total_avatars_in_lots_online = totalAvatars; + } + lotsOnlineJson.lots = lotSmallJson; return ApiResponse.Json(HttpStatusCode.OK, lotsOnlineJson); } @@ -313,7 +426,7 @@ public IActionResult GetTop100ByCategory(int shardId, LotCategory lotCategory) using (var da = api.DAFactory.Get()) { - var lots = da.LotTop100.GetByCategory(shardId, lotCategory); + var lots = da.LotTop100.GetByCategory(shardId, lotCategory).Take(100); if (lots == null) return ApiResponse.Json(HttpStatusCode.NotFound, new JSONLotError("Top100 lots not found")); List top100Lots = new List(); @@ -325,7 +438,8 @@ public IActionResult GetTop100ByCategory(int shardId, LotCategory lotCategory) rank = top100Lot.rank, shard_id = top100Lot.shard_id, lot_location = top100Lot.lot_location, - lot_name = top100Lot.lot_name + lot_name = top100Lot.lot_name, + lot_id = top100Lot.lot_id }); } var top100Json = new JSONTop100Lots(); @@ -354,7 +468,8 @@ public IActionResult GetTop100ByShard(int shardId) rank = top100Lot.rank, shard_id = top100Lot.shard_id, lot_location = top100Lot.lot_location, - lot_name = top100Lot.lot_name + lot_name = top100Lot.lot_name, + lot_id = top100Lot.lot_id }); } var top100Json = new JSONTop100Lots(); @@ -531,8 +646,20 @@ public JSONLotError(string errorString) error = errorString; } } + public class JSONLotsSmall + { + public List lots { get; set; } + } public class JSONLots { + public List lots { get; set; } + } + public class JSONLotsPage + { + public int page { get; set; } + public int total_pages { get; set; } + public int total_lots { get; set; } + public int lots_on_page { get; set; } public List lots { get; set; } } public class JSONLotsOnline @@ -543,15 +670,18 @@ public class JSONLotsOnline } public class JSONLotSmall { + public int lot_id { get; set; } public uint location { get; set; } public string name { get; set; } public string description { get; set; } public LotCategory category { get; set; } + public uint admit_mode { get; set; } public uint neighborhood_id { get; set; } public int avatars_in_lot { get; set; } } public class JSONLot { + public int lot_id { get; set; } public int shard_id { get; set; } public uint? owner_id { get; set; } public uint[] roommates { get; set; } @@ -575,5 +705,6 @@ public class JSONTop100Lot public int shard_id { get; set; } public string lot_name { get; set; } public uint? lot_location { get; set; } + public int? lot_id { get; set; } } } diff --git a/TSOClient/FSO.Server.Api.Core/Controllers/UserOAuthController.cs b/TSOClient/FSO.Server.Api.Core/Controllers/UserOAuthController.cs new file mode 100644 index 000000000..83b8a9d93 --- /dev/null +++ b/TSOClient/FSO.Server.Api.Core/Controllers/UserOAuthController.cs @@ -0,0 +1,128 @@ +using FSO.Server.Api.Core.Utils; +using FSO.Server.Common; +using FSO.Server.Servers.Api.JsonWebToken; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Web; +using System.Web.Http; + +namespace FSO.Server.Api.Core.Controllers +{ + [Route("userapi/oauth/token")] + [ApiController] + public class UserOAuthController : ControllerBase + { + [HttpPost] + public IActionResult CreateToken([FromForm] UserOAuthRequest userAuthRequest) + { + if (userAuthRequest == null) BadRequest(); + var api = Api.INSTANCE; + using (var da = api.DAFactory.Get()) + { + var user = da.Users.GetByUsername(userAuthRequest.username); + if (user == null || user.is_banned) return ApiResponse.Json(System.Net.HttpStatusCode.Unauthorized, new UserOAuthError("unauthorized_client", "user_credentials_invalid")); + var ip = ApiUtils.GetIP(Request); + var hashSettings = da.Users.GetAuthenticationSettings(user.user_id); + var isPasswordCorrect = PasswordHasher.Verify(userAuthRequest.password, new PasswordHash + { + data = hashSettings.data, + scheme = hashSettings.scheme_class + }); + //check if account is locked due to failed attempts + var accLock = da.Users.GetRemainingAuth(user.user_id, ip); + if (accLock != null && (accLock.active || accLock.count >= AuthLoginController.LockAttempts) && accLock.expire_time > Epoch.Now) + { + return ApiResponse.Json(System.Net.HttpStatusCode.OK, new UserOAuthError("unauthorized_client", "account_locked")); + } + //if the password is incorrect and check if user failed muli times and set a time out till next try. + if (!isPasswordCorrect) + { + var durations = AuthLoginController.LockDuration; + var failDelay = 60 * durations[Math.Min(durations.Length - 1, da.Users.FailedConsecutive(user.user_id, ip))]; + if (accLock == null) + { + da.Users.NewFailedAuth(user.user_id, ip, (uint)failDelay); + } + else + { + var remaining = da.Users.FailedAuth(accLock.attempt_id, (uint)failDelay, AuthLoginController.LockAttempts); + } + return ApiResponse.Json(System.Net.HttpStatusCode.OK, new UserOAuthError("unauthorized_client", "user_credentials_invalid")); + } + + //user passed the password check, and now creates the claim/token + da.Users.SuccessfulAuth(user.user_id, ip); + var claims = new List(); + + //set the permission level in the claim + switch (userAuthRequest.permission_level) + { + case 1: + claims.Add("userReadPermissions"); + break; + case 2: + claims.Add("userReadPermissions"); + claims.Add("userWritePermissions"); + break; + case 3: + claims.Add("userReadPermissions"); + claims.Add("userWritePermissions"); + claims.Add("userUpdatePermissions"); + break; + case 4: + claims.Add("userReadPermissions"); + claims.Add("userWritePermissions"); + claims.Add("userUpdatePermissions"); + claims.Add("userDeletePermissions"); + break; + default: + break; + } + + //set the user identity + JWTUser identity = new JWTUser + { + UserID = user.user_id, + UserName = user.username, + Claims = claims + }; + + //generate the the tokenen and send it in a JSON format as response + var generatedToken = api.JWT.CreateToken(identity); + return ApiResponse.Json(System.Net.HttpStatusCode.OK, new UserOAuthSuccess + { + access_token = generatedToken.Token, + expires_in = generatedToken.ExpiresIn + }); + } + + } + } + public class UserOAuthRequest + { + public int permission_level { get; set; } + public string username { get; set; } + public string password { get; set; } + } + public class UserOAuthError + { + public string error; + public string error_description; + public UserOAuthError(string errorString,string errorDescriptionString) + { + error = errorString; + error_description = errorDescriptionString; + } + } + public class UserOAuthSuccess + { + public string access_token { get; set; } + public int expires_in { get; set; } + } + +} \ No newline at end of file diff --git a/TSOClient/FSO.Server.Database/DA/AvatarClaims/IAvatarClaims.cs b/TSOClient/FSO.Server.Database/DA/AvatarClaims/IAvatarClaims.cs index 09d34a094..8b8236e7b 100644 --- a/TSOClient/FSO.Server.Database/DA/AvatarClaims/IAvatarClaims.cs +++ b/TSOClient/FSO.Server.Database/DA/AvatarClaims/IAvatarClaims.cs @@ -11,6 +11,7 @@ public interface IAvatarClaims DbAvatarClaim Get(int id); IEnumerable GetAll(); IEnumerable GetAllActiveAvatars(); + int? GetAllActiveAvatarsCount(); DbAvatarClaim GetByAvatarID(uint id); IEnumerable GetAllByOwner(string owner); diff --git a/TSOClient/FSO.Server.Database/DA/AvatarClaims/SqlAvatarClaims.cs b/TSOClient/FSO.Server.Database/DA/AvatarClaims/SqlAvatarClaims.cs index ccbafbe4b..e9648cbea 100644 --- a/TSOClient/FSO.Server.Database/DA/AvatarClaims/SqlAvatarClaims.cs +++ b/TSOClient/FSO.Server.Database/DA/AvatarClaims/SqlAvatarClaims.cs @@ -57,6 +57,10 @@ public IEnumerable GetAllActiveAvatars() return Context.Connection.Query("SELECT b.*, a.location FROM fso.fso_avatar_claims as a "+ "inner join fso.fso_avatars as b ON a.avatar_id = b.avatar_id;"); } + public int? GetAllActiveAvatarsCount() + { + return Context.Connection.Query("SELECT COUNT(*) FROM fso_avatar_claims").FirstOrDefault(); + } public DbAvatarClaim GetByAvatarID(uint id) { return Context.Connection.Query("SELECT * FROM fso_avatar_claims WHERE avatar_id = @id", new { id = id }).FirstOrDefault(); diff --git a/TSOClient/FSO.Server.Database/DA/Avatars/IAvatars.cs b/TSOClient/FSO.Server.Database/DA/Avatars/IAvatars.cs index db3904489..75794ede5 100644 --- a/TSOClient/FSO.Server.Database/DA/Avatars/IAvatars.cs +++ b/TSOClient/FSO.Server.Database/DA/Avatars/IAvatars.cs @@ -1,4 +1,5 @@ -using System; +using FSO.Server.Database.DA.Utils; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,13 +12,14 @@ public interface IAvatars uint Create(DbAvatar avatar); DbAvatar Get(uint id); - + List GetMultiple(uint[] id); bool Delete(uint id); int GetPrivacyMode(uint id); int GetModerationLevel(uint id); DbJobLevel GetCurrentJobLevel(uint avatar_id); List GetJobLevels(uint avatar_id); IEnumerable All(int shard_id); + PagedList AllByPage(int shard_id, int offset, int limit, string orderBy); List GetLivingInNhood(uint nhood_id); List GetPossibleCandidatesNhood(uint nhood_id); diff --git a/TSOClient/FSO.Server.Database/DA/Avatars/SqlAvatars.cs b/TSOClient/FSO.Server.Database/DA/Avatars/SqlAvatars.cs index 03be8c051..258f000fd 100644 --- a/TSOClient/FSO.Server.Database/DA/Avatars/SqlAvatars.cs +++ b/TSOClient/FSO.Server.Database/DA/Avatars/SqlAvatars.cs @@ -1,4 +1,5 @@ using Dapper; +using FSO.Server.Database.DA.Utils; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -12,6 +13,12 @@ public class SqlAvatars : AbstractSqlDA, IAvatars { public SqlAvatars(ISqlContext context) : base(context){ } + public PagedList AllByPage(int shard_id,int offset = 1, int limit = 100, string orderBy = "avatar_id") + { + var total = Context.Connection.Query("SELECT COUNT(*) FROM fso_avatars WHERE shard_id = @shard_id",new { shard_id = shard_id }).FirstOrDefault(); + var results = Context.Connection.Query("SELECT * FROM fso_avatars WHERE shard_id = @shard_id ORDER BY @order DESC LIMIT @offset, @limit", new { shard_id = shard_id, order = orderBy, offset = offset, limit = limit }); + return new PagedList(results, offset, total); + } public IEnumerable All(int shard_id){ return Context.Connection.Query("SELECT * FROM fso_avatars WHERE shard_id = @shard_id", new { shard_id = shard_id }); @@ -87,6 +94,21 @@ public List GetByUserId(uint user_id) ).ToList(); } + public List GetMultiple(uint[] id) + { + String inClause = "IN ("; + for (int i = 0; i < id.Length; i++) + { + inClause = inClause + "'" + id.ElementAt(i) + "'" + ","; + } + inClause = inClause.Substring(0, inClause.Length - 1); + inClause = inClause + ")"; + + return Context.Connection.Query( + "Select * from fso_avatars Where avatar_id "+ inClause + ).ToList(); + } + public List SearchExact(int shard_id, string name, int limit) { return Context.Connection.Query( diff --git a/TSOClient/FSO.Server.Database/DA/LotClaims/DbLotClaim.cs b/TSOClient/FSO.Server.Database/DA/LotClaims/DbLotClaim.cs index c8ba7488f..3112aaef1 100644 --- a/TSOClient/FSO.Server.Database/DA/LotClaims/DbLotClaim.cs +++ b/TSOClient/FSO.Server.Database/DA/LotClaims/DbLotClaim.cs @@ -28,6 +28,7 @@ public class DbLotActive public string description { get; set; } public uint location { get; set; } public uint neighborhood_id { get; set; } + public uint admit_mode { get; set; } public FSO.Common.Enum.LotCategory category { get; set; } public int active { get; set; } } diff --git a/TSOClient/FSO.Server.Database/DA/Lots/ILots.cs b/TSOClient/FSO.Server.Database/DA/Lots/ILots.cs index 52a9f6eb7..e01743962 100644 --- a/TSOClient/FSO.Server.Database/DA/Lots/ILots.cs +++ b/TSOClient/FSO.Server.Database/DA/Lots/ILots.cs @@ -1,4 +1,5 @@ using FSO.Common.Enum; +using FSO.Server.Database.DA.Utils; using System; using System.Collections.Generic; using System.Linq; @@ -10,6 +11,7 @@ namespace FSO.Server.Database.DA.Lots public interface ILots { IEnumerable All(int shard_id); + PagedList AllByPage(int shard_id, int offset, int limit, string orderBy); List GetLocationsInNhood(uint nhood_id); List GetCommunityLocations(int shard_id); List AllLocations(int shard_id); @@ -18,6 +20,7 @@ public interface ILots List GetAdjToLocation(int shard_id, uint location); DbLot GetByOwner(uint owner_id); DbLot Get(int id); + List GetMultiple(int[] ids); List Get(IEnumerable ids); uint Create(DbLot lot); bool Delete(int id); diff --git a/TSOClient/FSO.Server.Database/DA/Lots/SqlLots.cs b/TSOClient/FSO.Server.Database/DA/Lots/SqlLots.cs index ad416b76d..f731dc4e1 100644 --- a/TSOClient/FSO.Server.Database/DA/Lots/SqlLots.cs +++ b/TSOClient/FSO.Server.Database/DA/Lots/SqlLots.cs @@ -3,6 +3,7 @@ using FSO.Server.Common; using FSO.Server.Database.DA.Roommates; using FSO.Server.Database.DA.Shards; +using FSO.Server.Database.DA.Utils; using System; using System.Collections.Generic; using System.Data.SqlClient; @@ -20,6 +21,20 @@ public SqlLots(ISqlContext context) : base(context){ public DbLot Get(int id){ return Context.Connection.Query("SELECT * FROM fso_lots WHERE lot_id = @id", new { id = id }).FirstOrDefault(); } + public List GetMultiple(int[] id) + { + String inClause = "IN ("; + for (int i = 0; i < id.Length; i++) + { + inClause = inClause + "'" + id.ElementAt(i) + "'" + ","; + } + inClause = inClause.Substring(0, inClause.Length - 1); + inClause = inClause + ")"; + + return Context.Connection.Query( + "SELECT * FROM fso_lots WHERE lot_id " + inClause + ).ToList(); + } public List Get(IEnumerable ids) { @@ -98,6 +113,12 @@ public IEnumerable All(int shard_id) { return Context.Connection.Query("SELECT * FROM fso_lots WHERE shard_id = @shard_id", new { shard_id = shard_id }); } + public PagedList AllByPage(int shard_id, int offset = 1, int limit = 100, string orderBy = "lot_id") + { + var total = Context.Connection.Query("SELECT COUNT(*) FROM fso_lots WHERE shard_id = @shard_id", new { shard_id = shard_id }).FirstOrDefault(); + var results = Context.Connection.Query("SELECT * FROM fso_lots WHERE shard_id = @shard_id ORDER BY @order DESC LIMIT @offset, @limit", new { shard_id = shard_id, order = orderBy, offset = offset, limit = limit }); + return new PagedList(results, offset, total); + } public List AllLocations(int shard_id) { @@ -128,7 +149,7 @@ public DbLot GetByLocation(int shard_id, uint location) { return Context.Connection.Query("SELECT * FROM fso_lots WHERE location = @location AND shard_id = @shard_id", new { location = location, shard_id = shard_id }).FirstOrDefault(); } - + public List GetAdjToLocation(int shard_id, uint location) { return Context.Connection.Query("SELECT * FROM fso_lots WHERE "