-
Notifications
You must be signed in to change notification settings - Fork 0
Description
In addition to a new Project/Submission API, we need a new User API.
Old Structure
Here's what it used to look like
{
"events": [],
"minecraft_accounts": [],
"awards": [],
"permissions": [
"administrator"
],
"modrinth_id": "ehoQfHix",
"created": "2025-04-23T12:48:10.87Z",
"projects": [],
"pronouns": "sylv or it/its",
"discord_id": "209015289990348800",
"id": "702863390514610176",
"username": "sylv",
"display_name": "Sylv"
}We had these endpoints
get1("award/{award}", Award::getAwardType);
get1("event/{event}", Event::getEvent);
get1("event/{event}/submissions", Submission::getSubmissionsByEvent);
get1("events", Event::getEvents);
get1("events/current/registration", Event::getCurrentRegistrationEvent);
get1("events/current/development", Event::getCurrentDevelopmentEvent);
get1("events/current/prefreeze", Event::getCurrentPreFreezeEvent);
get1("events/active", Event::getActiveEvents);
get1("mcaccount/{mcaccount}", MinecraftAccount::getAccount);
get1("project/{project}", Project::getProject);
get1("submission/{submission}", Submission::getSubmission);
get1("user/{user}", User::getUser);
get1("user/{user}/projects", Project::getProjectsByUser);
get1("user/{user}/submissions", Submission::getSubmissionsByUser);
get1("user/{user}/submissions/{event}", Submission::getSubmissionsByUserAndEvent);
get1("user/{user}/awards", Award::getAwardsByUser);
post1("discord/register", RegistrationHandler::discordBotRegister);
get1("discord/oauth/modrinth", DiscordBotOAuthHandler::authModrinthAccount);
get1("discord/oauth/minecraft", DiscordBotOAuthHandler::authMinecraftAccount);
get1("discord/oauth/minecraft/challenge", DiscordBotOAuthHandler::getMicrosoftCodeChallenge);
post1("discord/submission/create/modrinth", DiscordBotSubmissionHandler::submitModrinth);
post1("discord/submission/modify/version/modrinth", DiscordBotSubmissionHandler::setVersionModrinth);
post1("discord/submission/delete", DiscordBotSubmissionHandler::unsubmit);
post1("discord/link", DiscordBotLinkHandler::link);
post1("discord/unlink", DiscordBotUnlinkHandler::unlink);
post1("discord/modify/username", DiscordBotProfileHandler::modifyUsername);
post1("discord/modify/displayname", DiscordBotProfileHandler::modifyDisplayName);
post1("discord/modify/pronouns", DiscordBotProfileHandler::modifyPronouns);
post1("discord/modify/avatar", DiscordBotProfileHandler::modifyAvatarUrl);
post1("discord/remove/pronouns", DiscordBotProfileHandler::removePronouns);
post1("discord/remove/avatar", DiscordBotProfileHandler::removeAvatarUrl);
post1("discord/project/user/invite", DiscordBotTeamManagementHandler::sendInvite);
post1("discord/project/user/accept", DiscordBotTeamManagementHandler::acceptInvite);
post1("discord/project/user/decline", DiscordBotTeamManagementHandler::declineInvite);
post1("discord/project/user/remove", DiscordBotTeamManagementHandler::removeMember);Now obviously, this is not easily extendable, and the fact that it's tied specifically to Discord is concerning on its own. For an initial API, this is fine (I kind of wish we'd called it v0), but we need something more useful.
Structure
Here's what a user will look like. This will be mostly the same with a few modifications for extensibility.
The following are the disallowed usernames:
modgardenmod.gardendefaultadminrootsystem- Any URIs due to their usage of
:(this may change in the future!)
Reserved usernames:
mod_garden(our "root" account)gardenbot(used by our bot for automation)tiny_pineapple(used as a placeholder for examples)ghost(used as a placeholder when an account does not exist)
Disallowed user IDs:
- Any user ID that is not five characters long or contains characters not in the 26 letter lowercase English Latin Script Alphabet
Reserved user IDs:
- All user IDs starting with
zzz(threezcharacters) (used by accounts that had snowflake IDs) - All user IDs ending in
botoracc(these are used by our reserved accounts) mgacc(used bymod_garden)grbot(used bygardenbot)abcde(used bytiny_pineapple, our example account)noacc(used byghost)
Clients SHOULD NOT attempt to query or create accounts with disallowed or reserved usernames or disallowed IDs. All such attempts MAY be denied. Disallowed usernames may be reserved in the future, and the list of disallowed and reserved usernames and user IDs is not final.
Note that all disallowed and reserved usernames and user IDs may change in the future. Clients MUST NOT validate user IDs or usernames as the server will return relevant information. Additionally, clients MUST NOT validate any Natural IDs including but not limited to in awards, events, submissions, and projects.
Endpoints
GET /user/{user_id}
The response body contains the user's data in JSON as defined above.
Example: /user/tiny_pineapple or /user/abcde
{
"id": "abcde",
"username": "tiny_pineapple",
"bio": {
"display_name": "Tiny Pineapple",
"pronouns": "it/its",
"description": "a tiny pineapple",
"fields": {
"Pineapples Converted": "3",
"Tiny Potatoes Converted": "2,839+"
}
},
"pronouns": "it/its",
"permissions": "1",
"created": "2025-04-23T12:48:10.87Z",
"integrations": {
"discord": {
"user_id": "1234567890"
},
"modrinth": {
"user_id": "aBCdEF3"
},
"minecraft": {
"accounts": [
"1b2ad345ff6c7da8eabde9b0"
]
}
},
"awards": [
"abcde"
],
"events": [
"abcde"
]
}GET /user/id/{user_slug}
The response body is of Content-Type text/plain and contains only the user's ID.
This is useful in authentication.
Example: /user/id/tiny_pineapple
abcde
{ "id": "abcde", // Clients should never validate usernames. // They should expect any valid UTF-8 from the server so that we may change to a new // username system in the future (such as DID:PLC which is a type of URI). "username": "tiny_pineapple", "bio": { "display_name": "Tiny Pineapple", "pronouns": "it/its", "description": "a tiny pineapple", // The domain SHOULD be cdn.modgarden.net. // If it is not, the server SHOULD ignore this field or throw an error. // The server MAY allow another domain name if it so chooses, in // which case the server SHOULD ignore the field or throw an error // if it encounters an unknown domain. "avatar_url": "https://cdn.modgarden.net/public/user/avatar/abcde.png", // Fields MUST have any key and any key-value pairs in their maps. // Additionally, fields MUST be of string type. // Outside of data types, clients MUST NOT validate fields as they are user-defined. "fields": { "Pineapples Converted": "3", "Tiny Potatoes Converted": "2,839+" } }, "permissions": "1", // A 64-bit unsigned bitfield integer for global permissions. "created": "2025-04-23T12:48:10.87Z", // Integrations MUST have any key and any key-value pairs in their maps. // Clients MUST fail safe when an unknown integration is encountered. "integrations": { "discord": { "user_id": "1234567890" }, "modrinth": { "user_id": "aBCdEF3" }, "minecraft": { "accounts": [ "1b2ad345ff6c7da8eabde9b0" ] } }, // All types of awards, including petals and theme awards. "awards": [ "abcde" // Award ID ], "events": [ "abcde" // Event ID ], "roles": [ "abcde" // Role ID ] }