Skip to content

Subreddit Wikis: usernotes

Erin edited this page Feb 1, 2022 · 15 revisions

/r/<sub>/wiki/usernotes

This documentation is a work in progress and may not be accurate.

This page contains a plain JSON object with the following properties:

  • ver - Settings format version. This document describes version 6. Higher values indicate a breaking change to this format. Always check this value, and never write old schema versions back to the wiki! See the section on schema version differences for more information on reading and updating previous schemas.
  • constants - An object with the following:
    • users - An array of moderator usernames (without the leading "u/", e.g. "geo1088") representing moderators who have added usernotes to people. Existing entries in this list are sacred: after a moderator is added to this list, they can't be moved or deleted without rewriting every stored usernote. Each individual note stores its responsible moderator as an index of this array. If you need to create a usernote on behalf of a user not in this array, add their name to the end; don't modify existing entries in this array unless you really need to. If you do modify existing entries, you're responsible for mapping the indexes you modify to ensure the notes retain the correct authors.
    • warnings - An array of note type names as strings. Just like the users, array, existing entries in this list are sacred and should never be modified unless you're willing to rewrite data for every note. These names correspond to entries in subreddit configuration; this is kinda a mess and needs to be documented. Each note stores its type as an index of this list. TODO
  • blob - A zlib-compressed, base64-encoded string that, when decoded and decompressed, gives a JSON object containing all usernotes.
Click to expand: Example of full JSON text
{
	"ver": 6,
	"constants": {
		"users": [
			"creesch",
			"geo1088"
		],
		"warnings": [
			"abusewarn",
			"gooduser",
			null,
			"ban"
		]
	},
	"blob": "eJyrVkpPzTc0sLBQsqpWyitWsoquVipRsjI0NbU0NjQwNzXQUcpTslLyLFEvVkhUKE5NLkotUSjJV0gtSy2qzM9LVdJRKgcq11HKBZK1sbW1AKKCF4Q="
}

Working with the blob

To convert from the blob string to a usable object/dictionary/etc, do the following:

  1. Decode the base64 string to binary data.
  2. Use zlib (or any other tool/library that implements its algorithms) to inflate the compressed binary data into a JSON string.
  3. Parse the JSON string into a workable value.

This will yield a JSON object described in the next section.

For example, a sample implementation in Node.js, using the built-in zlib package:

const {inflateSync} = require('zlib');
const blob = '...'; // This would be the full base64 string

// Read the base64 string into a Buffer
const buffer = Buffer.from(blob, 'base64');
// Inflate/decompress the binary data into a JSON string
const jsonString = inflateSync(buffer).toString('utf-8');
// Parse the string as JSON to get our final users object
const usersObject = JSON.parse(jsonString);

To convert a modified users object back to a blob for saving to the wiki, apply the process in reverse:

  1. Convert the object into a JSON string
  2. Use zlib or any compatible tool/library to deflate the JSON string into binary data
  3. Encode the binary data into a base64 string

Another sample implementation in Node.js:

const {deflateSync} = require('zlib');
const usersObject = {...}; // This would be the full users object

// Stringify the object
const jsonString = JSON.stringify(usersObject);
// Deflate/compress the string
const binaryData = zlib.deflateSync(jsonString);
// Convert binary data to a base64 string with a Buffer
const blob = Buffer.from(binaryData).toString('base64');

Working with note types

Toolbox reads its usernote types from the subreddit configuration's usernoteColors key. If this key is not present, the following array of note types is used instead:

[
	{"key": "gooduser", "color": "green", "text": "Good Contributor"},
	{"key": "spamwatch", "color": "fuchsia", "text": "Spam Watch"},
	{"key": "spamwarn", "color": "purple", "text": "Spam Warning"},
	{"key": "abusewarn", "color": "orange", "text": "Abuse Warning"},
	{"key": "ban", "color": "red", "text": "Ban"},
	{"key": "permban", "color": "darkred", "text": "Permanent Ban"},
	{"key": "botban", "color": "black", "text": "Bot Ban"}
]

When a usernote is created, the warnings array described on this page is checked. If the usernote type's key value is not in the warnings array, it is added at the end. The new usernote then stores its w property as the index of that key in the warnings array.

When reading usernotes, the type of the note is the type stored in the subreddit configuration with a key property equal to the item of the warnings array at the index specified by the note's w property.

For more information about modifying existing usernote types, see the subreddit configuration documentation.

The users object

When you've decompressed the blob, you'll get an object with the following format:

  • Top-level keys of the object are Reddit usernames. Each contains an object with the following:
    • ns - An array of note objects representing all the usernotes set on the user. Each note object in the array has the following:
      • t - The timestamp of the note's creation, a number of seconds (not milliseconds) from the epoch (1970-01-01 00:00 UTC).
      • n - The note text, a string.
      • m - A number representing the moderator who added this note. This number is an index of the constants.users array.
      • w - A number representing the type/color of the note. This number is an index of the constants.warnings array.
      • l - A string representing a link to where the note was added from. This string may use one of several special formats (listed below), and should not be assumed to be a full permalink. This key may also be null or not exist on notes without stored links.
Click to expand: Example of a the object in JSON
{
	"geo1088": {
		"ns": [
			{
				"t": 1559310750,
				"n": "It's a secret to everyone",
				"w": 1,
				"m": 1
			},
			{
				"t": 1559310836,
				"n": "All your usernote are belong to us",
				"w": 2,
				"m": 0,
				"l": "l,bfgb5y,eldfyai"
			}
		]
	},
	"creesch": {
		"ns": [
			{
				"t": 1559310623,
				"n": "heh",
				"w": 0,
				"m": 1,
				"l": null
			}
		]
	}
}

Link string formats

To save space, Toolbox avoids storing full URLs in usernotes when it can. Instead, shorthand formats are used and converted into full URLs when read. In the following examples, things in (PARENTHESES) are stand-ins for substrings; all other characters are literal.

  • l,(SUBMISSION_ID),(COMMENT_ID) represents a link to a comment, and can be expanded to https://www.reddit.com/comments/(SUBMISSION_ID)/_/(COMMENT_ID).
  • l,(SUBMISSION_ID) represents a link to a submission, and can be expanded to https://www.reddit.com/comments/(SUBMISSION_ID) or https://redd.it/(SUBMISSION_ID).
  • m,(THREAD_ID) represents a link to an old modmail thread and is equivalent to https://www.reddit.com/message/messages/(THREAD_ID).
  • Full URLs are sometimes stored directly. Toolbox itself stores links to new modmail threads as full URLs, for example. Writing full URLs other than new modmail permalinks is discouraged—don't introduce external URLs, and use the shorthand formats for other resources on Reddit. However, for legacy support, you should support reading arbitrary URLs (not just new modmail links), and optionally convert them to the shorthand formats when applicable.

Known schema ver differences

Never write data in old schema versions. If you read an old schema version, update the data to the latest version documented here before writing back to the wiki.

  • 5: Identical to 6, except the blob key is not provided. Instead, the data key is provided, which contains the uncompressed version of blob.
  • 4: Identical to 5, except the t key on each note object is specified in milliseconds instead of seconds.