diff --git a/Foxnouns.Backend/Controllers/DeleteUserController.cs b/Foxnouns.Backend/Controllers/DeleteUserController.cs index d1c8e62..b611c35 100644 --- a/Foxnouns.Backend/Controllers/DeleteUserController.cs +++ b/Foxnouns.Backend/Controllers/DeleteUserController.cs @@ -1,17 +1,3 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . using Foxnouns.Backend.Database; using Foxnouns.Backend.Middleware; using Microsoft.AspNetCore.Mvc; diff --git a/Foxnouns.Backend/Controllers/InternalController.cs b/Foxnouns.Backend/Controllers/InternalController.cs index 3954547..85bc774 100644 --- a/Foxnouns.Backend/Controllers/InternalController.cs +++ b/Foxnouns.Backend/Controllers/InternalController.cs @@ -38,8 +38,6 @@ public partial class InternalController(DatabaseContext db) : ControllerBase { if (template.StartsWith("api/v2")) template = template["api/v2".Length..]; - else if (template.StartsWith("api/v1")) - template = template["api/v1".Length..]; template = PathVarRegex() .Replace(template, "{id}") // Replace all path variables (almost always IDs) with `{id}` .Replace("@me", "{id}"); // Also replace hardcoded `@me` with `{id}` diff --git a/Foxnouns.Backend/Controllers/NotificationsController.cs b/Foxnouns.Backend/Controllers/NotificationsController.cs index 873344c..f258b3c 100644 --- a/Foxnouns.Backend/Controllers/NotificationsController.cs +++ b/Foxnouns.Backend/Controllers/NotificationsController.cs @@ -1,17 +1,3 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Middleware; diff --git a/Foxnouns.Backend/Controllers/V1/UsersV1Controller.cs b/Foxnouns.Backend/Controllers/V1/UsersV1Controller.cs new file mode 100644 index 0000000..e11e490 --- /dev/null +++ b/Foxnouns.Backend/Controllers/V1/UsersV1Controller.cs @@ -0,0 +1,16 @@ +using Foxnouns.Backend.Database.Models; +using Foxnouns.Backend.Services.V1; +using Microsoft.AspNetCore.Mvc; + +namespace Foxnouns.Backend.Controllers.V1; + +[Route("/api/v1/users")] +public class UsersV1Controller(UsersV1Service usersV1Service) : ApiControllerBase +{ + [HttpGet("{userRef}")] + public async Task GetUserAsync(string userRef, CancellationToken ct = default) + { + User user = await usersV1Service.ResolveUserAsync(userRef, CurrentToken, ct); + return Ok(await usersV1Service.RenderUserAsync(user)); + } +} diff --git a/Foxnouns.Backend/Controllers/V1/V1ReadController.cs b/Foxnouns.Backend/Controllers/V1/V1ReadController.cs deleted file mode 100644 index 5f69c20..0000000 --- a/Foxnouns.Backend/Controllers/V1/V1ReadController.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto.V1; -using Foxnouns.Backend.Services.V1; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; - -namespace Foxnouns.Backend.Controllers.V1; - -[Route("/api/v1")] -public class V1ReadController( - UsersV1Service usersV1Service, - MembersV1Service membersV1Service, - DatabaseContext db -) : ApiControllerBase -{ - [HttpGet("users/{userRef}")] - public async Task GetUserAsync(string userRef, CancellationToken ct = default) - { - User user = await usersV1Service.ResolveUserAsync(userRef, CurrentToken, ct); - return Ok( - await usersV1Service.RenderUserAsync( - user, - CurrentToken, - renderMembers: true, - renderFlags: true, - ct: ct - ) - ); - } - - [HttpGet("members/{id}")] - public async Task GetMemberAsync(string id, CancellationToken ct = default) - { - Member member = await membersV1Service.ResolveMemberAsync(id, ct); - return Ok( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - renderFlags: true, - ct: ct - ) - ); - } - - [HttpGet("users/{userRef}/members")] - public async Task GetUserMembersAsync( - string userRef, - CancellationToken ct = default - ) - { - User user = await usersV1Service.ResolveUserAsync(userRef, CurrentToken, ct); - List members = await db - .Members.Where(m => m.UserId == user.Id) - .OrderBy(m => m.Name) - .ToListAsync(ct); - - List responses = []; - foreach (Member member in members) - { - responses.Add( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - user, - renderFlags: true, - ct: ct - ) - ); - } - - return Ok(responses); - } - - [HttpGet("users/{userRef}/members/{memberRef}")] - public async Task GetUserMemberAsync( - string userRef, - string memberRef, - CancellationToken ct = default - ) - { - Member member = await membersV1Service.ResolveMemberAsync( - userRef, - memberRef, - CurrentToken, - ct - ); - return Ok( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - renderFlags: true, - ct: ct - ) - ); - } -} diff --git a/Foxnouns.Backend/Dto/V1/Member.cs b/Foxnouns.Backend/Dto/V1/Member.cs deleted file mode 100644 index c745187..0000000 --- a/Foxnouns.Backend/Dto/V1/Member.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// ReSharper disable NotAccessedPositionalProperty.Global -using Foxnouns.Backend.Database; -using Newtonsoft.Json; - -namespace Foxnouns.Backend.Dto.V1; - -public record PartialMember( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns -); - -public record MemberResponse( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns, - ProfileField[] Fields, - PrideFlag[] Flags, - PartialUser User, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] bool? Unlisted -); - -public record PartialUser( - string Id, - Snowflake IdNew, - string Name, - string? DisplayName, - string? Avatar, - Dictionary CustomPreferences -); diff --git a/Foxnouns.Backend/Dto/V1/User.cs b/Foxnouns.Backend/Dto/V1/User.cs index c212d97..eab4c29 100644 --- a/Foxnouns.Backend/Dto/V1/User.cs +++ b/Foxnouns.Backend/Dto/V1/User.cs @@ -1,18 +1,3 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - // ReSharper disable NotAccessedPositionalProperty.Global using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; @@ -36,8 +21,6 @@ public record UserResponse( FieldEntry[] Names, PronounEntry[] Pronouns, ProfileField[] Fields, - PrideFlag[] Flags, - PartialMember[] Members, int? UtcOffset, Dictionary CustomPreferences ); @@ -92,5 +75,3 @@ public record PronounEntry(string Pronouns, string? DisplayText, string Status) )) .ToArray(); } - -public record PrideFlag(string Id, Snowflake IdNew, string Hash, string Name, string? Description); diff --git a/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs b/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs index 426ec12..86b4a82 100644 --- a/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs +++ b/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs @@ -130,8 +130,7 @@ public static class WebApplicationExtensions .AddTransient() .AddTransient() // Legacy services - .AddScoped() - .AddScoped(); + .AddScoped(); if (!config.Logging.EnableMetrics) services.AddHostedService(); diff --git a/Foxnouns.Backend/Services/V1/MembersV1Service.cs b/Foxnouns.Backend/Services/V1/MembersV1Service.cs deleted file mode 100644 index 632226c..0000000 --- a/Foxnouns.Backend/Services/V1/MembersV1Service.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto.V1; -using Microsoft.EntityFrameworkCore; -using FieldEntry = Foxnouns.Backend.Dto.V1.FieldEntry; -using PrideFlag = Foxnouns.Backend.Dto.V1.PrideFlag; - -namespace Foxnouns.Backend.Services.V1; - -public class MembersV1Service(DatabaseContext db, UsersV1Service usersV1Service) -{ - public async Task ResolveMemberAsync(string id, CancellationToken ct = default) - { - Member? member; - if (Snowflake.TryParse(id, out Snowflake? sf)) - { - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Id == sf && !m.User.Deleted, ct); - if (member != null) - return member; - } - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.LegacyId == id && !m.User.Deleted, ct); - if (member != null) - return member; - - throw new ApiError.NotFound("No member with that ID found.", ErrorCode.MemberNotFound); - } - - public async Task ResolveMemberAsync( - string userRef, - string memberRef, - Token? token, - CancellationToken ct = default - ) - { - User user = await usersV1Service.ResolveUserAsync(userRef, token, ct); - - Member? member; - if (Snowflake.TryParse(memberRef, out Snowflake? sf)) - { - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Id == sf && m.UserId == user.Id, ct); - if (member != null) - return member; - } - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.LegacyId == memberRef && m.UserId == user.Id, ct); - if (member != null) - return member; - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Name == memberRef && m.UserId == user.Id, ct); - if (member != null) - return member; - - throw new ApiError.NotFound( - "No member with that ID or name found.", - ErrorCode.MemberNotFound - ); - } - - public async Task RenderMemberAsync( - Member m, - Token? token = default, - User? user = null, - bool renderFlags = true, - CancellationToken ct = default - ) - { - user ??= m.User; - bool renderUnlisted = m.UserId == token?.UserId; - - List flags = renderFlags - ? await db.MemberFlags.Where(f => f.MemberId == m.Id).OrderBy(f => f.Id).ToListAsync(ct) - : []; - - return new MemberResponse( - m.LegacyId, - m.Id, - m.Sid, - m.Name, - m.DisplayName, - m.Bio, - m.Avatar, - m.Links, - Names: FieldEntry.FromEntries(m.Names, user.CustomPreferences), - Pronouns: PronounEntry.FromPronouns(m.Pronouns, user.CustomPreferences), - Fields: ProfileField.FromFields(m.Fields, user.CustomPreferences), - Flags: flags - .Where(f => f.PrideFlag.Hash != null) - .Select(f => new PrideFlag( - f.PrideFlag.LegacyId, - f.PrideFlag.Id, - f.PrideFlag.Hash!, - f.PrideFlag.Name, - f.PrideFlag.Description - )) - .ToArray(), - User: UsersV1Service.RenderPartialUser(user), - Unlisted: renderUnlisted ? m.Unlisted : null - ); - } -} diff --git a/Foxnouns.Backend/Services/V1/UsersV1Service.cs b/Foxnouns.Backend/Services/V1/UsersV1Service.cs index 34163a6..7492256 100644 --- a/Foxnouns.Backend/Services/V1/UsersV1Service.cs +++ b/Foxnouns.Backend/Services/V1/UsersV1Service.cs @@ -1,23 +1,8 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto.V1; using Microsoft.EntityFrameworkCore; using FieldEntry = Foxnouns.Backend.Dto.V1.FieldEntry; -using PrideFlag = Foxnouns.Backend.Dto.V1.PrideFlag; namespace Foxnouns.Backend.Services.V1; @@ -64,26 +49,8 @@ public class UsersV1Service(DatabaseContext db) ); } - public async Task RenderUserAsync( - User user, - Token? token = null, - bool renderMembers = true, - bool renderFlags = true, - CancellationToken ct = default - ) + public async Task RenderUserAsync(User user) { - bool isSelfUser = user.Id == token?.UserId; - renderMembers = renderMembers && (isSelfUser || !user.ListHidden); - - // Only fetch members if we're rendering members (duh) - List members = renderMembers - ? await db.Members.Where(m => m.UserId == user.Id).OrderBy(m => m.Name).ToListAsync(ct) - : []; - - List flags = renderFlags - ? await db.UserFlags.Where(f => f.UserId == user.Id).OrderBy(f => f.Id).ToListAsync(ct) - : []; - int? utcOffset = null; if ( user.Timezone != null @@ -103,67 +70,23 @@ public class UsersV1Service(DatabaseContext db) user.MemberTitle, user.Avatar, user.Links, - Names: FieldEntry.FromEntries(user.Names, user.CustomPreferences), - Pronouns: PronounEntry.FromPronouns(user.Pronouns, user.CustomPreferences), - Fields: ProfileField.FromFields(user.Fields, user.CustomPreferences), - Flags: flags - .Where(f => f.PrideFlag.Hash != null) - .Select(f => new PrideFlag( - f.PrideFlag.LegacyId, - f.PrideFlag.Id, - f.PrideFlag.Hash!, - f.PrideFlag.Name, - f.PrideFlag.Description - )) - .ToArray(), - Members: members.Select(m => RenderPartialMember(m, user.CustomPreferences)).ToArray(), + FieldEntry.FromEntries(user.Names, user.CustomPreferences), + PronounEntry.FromPronouns(user.Pronouns, user.CustomPreferences), + ProfileField.FromFields(user.Fields, user.CustomPreferences), utcOffset, - CustomPreferences: RenderCustomPreferences(user.CustomPreferences) - ); - } - - private static Dictionary RenderCustomPreferences( - Dictionary customPreferences - ) => - customPreferences - .Select(x => - ( - x.Value.LegacyId, - new CustomPreference( - x.Value.Icon, - x.Value.Tooltip, - x.Value.Size, - x.Value.Muted, - x.Value.Favourite + user.CustomPreferences.Select(x => + ( + x.Value.LegacyId, + new CustomPreference( + x.Value.Icon, + x.Value.Tooltip, + x.Value.Size, + x.Value.Muted, + x.Value.Favourite + ) ) ) - ) - .ToDictionary(); - - private static PartialMember RenderPartialMember( - Member m, - Dictionary customPreferences - ) => - new( - m.LegacyId, - m.Id, - m.Sid, - m.Name, - m.DisplayName, - m.Bio, - m.Avatar, - m.Links, - Names: FieldEntry.FromEntries(m.Names, customPreferences), - Pronouns: PronounEntry.FromPronouns(m.Pronouns, customPreferences) - ); - - public static PartialUser RenderPartialUser(User user) => - new( - user.LegacyId, - user.Id, - user.Username, - user.DisplayName, - user.Avatar, - CustomPreferences: RenderCustomPreferences(user.CustomPreferences) + .ToDictionary() ); + } } diff --git a/Foxnouns.Backend/Services/V1/V1Utils.cs b/Foxnouns.Backend/Services/V1/V1Utils.cs index 2e52316..eb8d9c0 100644 --- a/Foxnouns.Backend/Services/V1/V1Utils.cs +++ b/Foxnouns.Backend/Services/V1/V1Utils.cs @@ -1,17 +1,3 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; diff --git a/Foxnouns.Backend/config.example.ini b/Foxnouns.Backend/config.example.ini index 9c6097e..7522cba 100644 --- a/Foxnouns.Backend/config.example.ini +++ b/Foxnouns.Backend/config.example.ini @@ -1,7 +1,7 @@ ; The host the server will listen on Host = localhost ; The port the server will listen on -Port = 6000 +Port = 5000 ; The base *external* URL BaseUrl = https://pronouns.localhost ; The base URL for media, without a trailing slash. This must be publicly accessible. diff --git a/Foxnouns.Frontend/.env.example b/Foxnouns.Frontend/.env.example index 2931832..d79c672 100644 --- a/Foxnouns.Frontend/.env.example +++ b/Foxnouns.Frontend/.env.example @@ -1,7 +1,7 @@ -# Example .env file--DO NOT EDIT, copy to .env or .env.local then edit +# Example .env file--DO NOT EDIT PUBLIC_LANGUAGE=en PUBLIC_BASE_URL=https://pronouns.cc PUBLIC_SHORT_URL=https://prns.cc PUBLIC_API_BASE=https://pronouns.cc/api PRIVATE_API_HOST=http://localhost:5003/api -PRIVATE_INTERNAL_API_HOST=http://localhost:6000/api +PRIVATE_INTERNAL_API_HOST=http://localhost:5000/api diff --git a/rate/handler.go b/rate/handler.go index 311b5b8..7ab0b59 100644 --- a/rate/handler.go +++ b/rate/handler.go @@ -38,7 +38,7 @@ func (hn *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // all public api endpoints are prefixed with this - if !strings.HasPrefix(r.URL.Path, "/api/v2") && !strings.HasPrefix(r.URL.Path, "/api/v1") { + if !strings.HasPrefix(r.URL.Path, "/api/v2") { w.WriteHeader(http.StatusNotFound) return } diff --git a/rate/proxy-config.example.json b/rate/proxy-config.example.json index 1ec9e59..427acef 100644 --- a/rate/proxy-config.example.json +++ b/rate/proxy-config.example.json @@ -1,6 +1,6 @@ { "port": 5003, - "proxy_target": "http://localhost:6000", + "proxy_target": "http://localhost:5000", "debug": true, "powered_by": "5 gay rats" }