Skip to content

Commit 41f7555

Browse files
committed
Ability to see previous usernames via API
1 parent 08bbe52 commit 41f7555

5 files changed

Lines changed: 107 additions & 0 deletions

File tree

Refresh.Database/GameDatabaseContext.Registration.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ namespace Refresh.Database;
88

99
public partial class GameDatabaseContext // Registration
1010
{
11+
private IQueryable<PreviousUsername> PreviousUsernamesIncluded => this.PreviousUsernames
12+
.Include(p => p.User);
13+
1114
public GameUser CreateUser(string username, string emailAddress, bool skipChecks = false)
1215
{
1316
if (!skipChecks)
@@ -110,6 +113,21 @@ public bool IsUsernameTaken(string username, GameUser? userToName = null)
110113

111114
return false;
112115
}
116+
117+
public bool WasUsernamePreviouslyTaken(string username)
118+
{
119+
return this.PreviousUsernames.Any(u => u.Username == username);
120+
}
121+
122+
public DatabaseList<PreviousUsername> GetPreviousUsernameRecordsForUsername(string username, int skip, int count)
123+
{
124+
return new(this.PreviousUsernamesIncluded.Where(u => u.Username == username), skip, count);
125+
}
126+
127+
public DatabaseList<PreviousUsername> GetPreviousUsernameRecordsByUser(GameUser user, int skip, int count)
128+
{
129+
return new(this.PreviousUsernamesIncluded.Where(u => u.UserId == user.UserId), skip, count);
130+
}
113131

114132
public bool IsEmailTaken(string emailAddress)
115133
{

Refresh.Interfaces.APIv3/Endpoints/Admin/AdminUserApiEndpoints.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,31 @@ public ApiListResponse<ApiExtendedGameUserResponse> GetExtendedUsers(RequestCont
5050
return list;
5151
}
5252

53+
[ApiV3Endpoint("admin/previousUsernames/byName/{username}"), MinimumRole(GameUserRole.Moderator)]
54+
[DocSummary("Gets all users (with extended information) who have once used the specified username.")]
55+
[DocUsesPageData]
56+
public ApiListResponse<ApiExtendedPreviousUsernameResponse> GetExtendedPreviousUsernamesByUsername(RequestContext context,
57+
GameDatabaseContext database, IDataStore dataStore, DataContext dataContext, string username)
58+
{
59+
(int skip, int count) = context.GetPageData();
60+
DatabaseList<PreviousUsername> previousNames = database.GetPreviousUsernameRecordsForUsername(username, skip, count);
61+
return DatabaseListExtensions.FromOldList<ApiExtendedPreviousUsernameResponse, PreviousUsername>(previousNames, dataContext);
62+
}
63+
64+
[ApiV3Endpoint("admin/previousUsernames/byUserUuid/{uuid}"), MinimumRole(GameUserRole.Moderator)]
65+
[DocSummary("Gets all previous usernames which have once been used by the specified user.")]
66+
[DocUsesPageData]
67+
public ApiListResponse<ApiExtendedPreviousUsernameResponse> GetExtendedPreviousUsernamesByUser(RequestContext context,
68+
GameDatabaseContext database, IDataStore dataStore, DataContext dataContext, string uuid)
69+
{
70+
GameUser? user = database.GetUserByUuid(uuid);
71+
if (user == null) return ApiNotFoundError.UserMissingError;
72+
73+
(int skip, int count) = context.GetPageData();
74+
DatabaseList<PreviousUsername> previousNames = database.GetPreviousUsernameRecordsByUser(user, skip, count);
75+
return DatabaseListExtensions.FromOldList<ApiExtendedPreviousUsernameResponse, PreviousUsername>(previousNames, dataContext);
76+
}
77+
5378
[ApiV3Endpoint("admin/users/{idType}/{id}/resetPassword", HttpMethods.Put), MinimumRole(GameUserRole.Moderator)]
5479
[DocSummary("Resets a user's password by their UUID or username.")]
5580
[DocError(typeof(ApiNotFoundError), ApiNotFoundError.UserMissingErrorWhen)]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Refresh.Core.Types.Data;
2+
using Refresh.Database.Models.Users;
3+
4+
namespace Refresh.Interfaces.APIv3.Endpoints.DataTypes.Response.Users;
5+
6+
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
7+
public class ApiExtendedPreviousUsernameResponse : ApiPreviousUsernameResponse, IDataConvertableFrom<ApiExtendedPreviousUsernameResponse, PreviousUsername>
8+
{
9+
public new static ApiExtendedPreviousUsernameResponse? FromOld(PreviousUsername? old, DataContext dataContext)
10+
{
11+
if (old == null) return null;
12+
13+
return new ApiExtendedPreviousUsernameResponse
14+
{
15+
Username = old.Username,
16+
User = ApiExtendedGameUserResponse.FromOld(old.User, dataContext)!,
17+
ReplacedAt = old.ReplacedAt,
18+
};
19+
}
20+
21+
public new static IEnumerable<ApiExtendedPreviousUsernameResponse> FromOldList(IEnumerable<PreviousUsername> oldList, DataContext dataContext)
22+
=> oldList.Select(old => FromOld(old, dataContext)).ToList()!;
23+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Refresh.Core.Types.Data;
2+
using Refresh.Database.Models.Users;
3+
4+
namespace Refresh.Interfaces.APIv3.Endpoints.DataTypes.Response.Users;
5+
6+
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
7+
public class ApiPreviousUsernameResponse : IApiResponse, IDataConvertableFrom<ApiPreviousUsernameResponse, PreviousUsername>
8+
{
9+
public required string Username { get; set; }
10+
public required ApiGameUserResponse User { get; set; }
11+
public required DateTimeOffset ReplacedAt { get; set; }
12+
13+
public static ApiPreviousUsernameResponse? FromOld(PreviousUsername? old, DataContext dataContext)
14+
{
15+
if (old == null) return null;
16+
17+
return new ApiPreviousUsernameResponse
18+
{
19+
Username = old.Username,
20+
User = ApiGameUserResponse.FromOld(old.User, dataContext)!,
21+
ReplacedAt = old.ReplacedAt,
22+
};
23+
}
24+
25+
public static IEnumerable<ApiPreviousUsernameResponse> FromOldList(IEnumerable<PreviousUsername> oldList, DataContext dataContext)
26+
=> oldList.Select(old => FromOld(old, dataContext)).ToList()!;
27+
}
28+

Refresh.Interfaces.APIv3/Endpoints/UserApiEndpoints.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Refresh.Database.Models.Authentication;
1616
using Refresh.Database.Models.Pins;
1717
using Refresh.Database.Models.Users;
18+
using Refresh.Interfaces.APIv3.Documentation.Attributes;
1819
using Refresh.Interfaces.APIv3.Documentation.Descriptions;
1920
using Refresh.Interfaces.APIv3.Endpoints.ApiTypes;
2021
using Refresh.Interfaces.APIv3.Endpoints.ApiTypes.Errors;
@@ -99,6 +100,18 @@ public ApiResponse<ApiExtendedGameUserResponse> GetMyUser(RequestContext context
99100
return ApiExtendedGameUserResponse.FromOld(user, dataContext);
100101
}
101102

103+
[ApiV3Endpoint("users/me/previousUsernames"), MinimumRole(GameUserRole.Moderator)]
104+
[DocSummary("Gets all previous usernames which you have used.")]
105+
[DocUsesPageData]
106+
[RateLimitSettings(120, 35, 80, "me-api")] // TODO remove when we clean up rate-limit stats
107+
public ApiListResponse<ApiExtendedPreviousUsernameResponse> GetMyPreviousUsernames(RequestContext context,
108+
GameDatabaseContext database, IDataStore dataStore, DataContext dataContext, GameUser user)
109+
{
110+
(int skip, int count) = context.GetPageData();
111+
DatabaseList<PreviousUsername> previousNames = database.GetPreviousUsernameRecordsByUser(user, skip, count);
112+
return DatabaseListExtensions.FromOldList<ApiExtendedPreviousUsernameResponse, PreviousUsername>(previousNames, dataContext);
113+
}
114+
102115
[ApiV3Endpoint("users/me", HttpMethods.Patch)]
103116
[DocSummary("Updates your profile with the given data")]
104117
[RateLimitSettings(UserModificationEndpointLimits.TimeoutDuration, UserModificationEndpointLimits.ApiRequestAmount,

0 commit comments

Comments
 (0)