diff --git a/Foxnouns.Backend/Controllers/DeleteUserController.cs b/Foxnouns.Backend/Controllers/DeleteUserController.cs
index b611c35..d1c8e62 100644
--- a/Foxnouns.Backend/Controllers/DeleteUserController.cs
+++ b/Foxnouns.Backend/Controllers/DeleteUserController.cs
@@ -1,3 +1,17 @@
+// 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 85bc774..3954547 100644
--- a/Foxnouns.Backend/Controllers/InternalController.cs
+++ b/Foxnouns.Backend/Controllers/InternalController.cs
@@ -38,6 +38,8 @@ 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 f258b3c..873344c 100644
--- a/Foxnouns.Backend/Controllers/NotificationsController.cs
+++ b/Foxnouns.Backend/Controllers/NotificationsController.cs
@@ -1,3 +1,17 @@
+// 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
deleted file mode 100644
index e11e490..0000000
--- a/Foxnouns.Backend/Controllers/V1/UsersV1Controller.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-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
new file mode 100644
index 0000000..5f69c20
--- /dev/null
+++ b/Foxnouns.Backend/Controllers/V1/V1ReadController.cs
@@ -0,0 +1,111 @@
+// 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
new file mode 100644
index 0000000..c745187
--- /dev/null
+++ b/Foxnouns.Backend/Dto/V1/Member.cs
@@ -0,0 +1,59 @@
+// 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 eab4c29..c212d97 100644
--- a/Foxnouns.Backend/Dto/V1/User.cs
+++ b/Foxnouns.Backend/Dto/V1/User.cs
@@ -1,3 +1,18 @@
+// 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;
@@ -21,6 +36,8 @@ public record UserResponse(
FieldEntry[] Names,
PronounEntry[] Pronouns,
ProfileField[] Fields,
+ PrideFlag[] Flags,
+ PartialMember[] Members,
int? UtcOffset,
Dictionary CustomPreferences
);
@@ -75,3 +92,5 @@ 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 86b4a82..426ec12 100644
--- a/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs
+++ b/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs
@@ -130,7 +130,8 @@ 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
new file mode 100644
index 0000000..632226c
--- /dev/null
+++ b/Foxnouns.Backend/Services/V1/MembersV1Service.cs
@@ -0,0 +1,125 @@
+// 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 7492256..34163a6 100644
--- a/Foxnouns.Backend/Services/V1/UsersV1Service.cs
+++ b/Foxnouns.Backend/Services/V1/UsersV1Service.cs
@@ -1,8 +1,23 @@
+// 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;
@@ -49,8 +64,26 @@ public class UsersV1Service(DatabaseContext db)
);
}
- public async Task RenderUserAsync(User user)
+ public async Task RenderUserAsync(
+ User user,
+ Token? token = null,
+ bool renderMembers = true,
+ bool renderFlags = true,
+ CancellationToken ct = default
+ )
{
+ 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
@@ -70,23 +103,67 @@ public class UsersV1Service(DatabaseContext db)
user.MemberTitle,
user.Avatar,
user.Links,
- FieldEntry.FromEntries(user.Names, user.CustomPreferences),
- PronounEntry.FromPronouns(user.Pronouns, user.CustomPreferences),
- ProfileField.FromFields(user.Fields, user.CustomPreferences),
+ 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(),
utcOffset,
- 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()
+ 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
+ )
+ )
+ )
+ .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)
+ );
}
diff --git a/Foxnouns.Backend/Services/V1/V1Utils.cs b/Foxnouns.Backend/Services/V1/V1Utils.cs
index eb8d9c0..2e52316 100644
--- a/Foxnouns.Backend/Services/V1/V1Utils.cs
+++ b/Foxnouns.Backend/Services/V1/V1Utils.cs
@@ -1,3 +1,17 @@
+// 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 7522cba..9c6097e 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 = 5000
+Port = 6000
; 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 d79c672..2931832 100644
--- a/Foxnouns.Frontend/.env.example
+++ b/Foxnouns.Frontend/.env.example
@@ -1,7 +1,7 @@
-# Example .env file--DO NOT EDIT
+# Example .env file--DO NOT EDIT, copy to .env or .env.local then 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:5000/api
+PRIVATE_INTERNAL_API_HOST=http://localhost:6000/api
diff --git a/rate/handler.go b/rate/handler.go
index 7ab0b59..311b5b8 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") {
+ if !strings.HasPrefix(r.URL.Path, "/api/v2") && !strings.HasPrefix(r.URL.Path, "/api/v1") {
w.WriteHeader(http.StatusNotFound)
return
}
diff --git a/rate/proxy-config.example.json b/rate/proxy-config.example.json
index 427acef..1ec9e59 100644
--- a/rate/proxy-config.example.json
+++ b/rate/proxy-config.example.json
@@ -1,6 +1,6 @@
{
"port": 5003,
- "proxy_target": "http://localhost:5000",
+ "proxy_target": "http://localhost:6000",
"debug": true,
"powered_by": "5 gay rats"
}