/anarq

An Open Source alternative to Facebook, Reddit and Disqus

Primary LanguageHTML

AnarQ - An Open Source Social Media Platform

AnarQ is an Open Source social media platform that you can install on your local server, providing you with feeds, posts, profiles, the ability to moderate posts, etc. Its most basic functionality is that of serving as a forum HTTP backend web API, but it goes way beyond the capabilities of a plain forum, by including social gaming elements, such as likes, profiles, voting, etc. It's arguably in such a regard more a social media platform, than a traditional forum, competing with social media platforms such as Reddit, Facebook and Twitter.

Its name is a play upon the two Greek words "an" and "archy" implying "no leaders" or "no hierarchy", adding the Q in its name implies U. It is Open Source, but you will need a license of Magic to run it.

Implementation details

The system is implemented in Hyperlambda, on top of .Net 5, and uses MySQL or MariaDB as its backing database. The system is a 100% pure HTML Web API, allowing you to implement any client technology you see fit on top of it.

Configuring

In order to configure AnarQ you'll need to configure an SMTP server, since the systems frequently sends emails to its registered users, to among other things have users verify their email address during registrations, etc. To see how to configure this, visit the link below

In addition AnarQ requires its own configuration settings. You can find an example below.

  "anarq": {
    "frontend": {
      "url": "https://anarq.org"
    },
    "cooldown-minues": 5
  },

Paste in the above into your configuration file, just above the magic parts, and modify it as needed. Modify the actual frontend url according to where you have your frontend running. The cooldown-minutes part above is the number of minutes users must wait between each OP post they submit to the site. If it is -1, users can post as frequently as they wish.

The system also contains a whole range of email templates, intended for you to edit and modify as you see fit, according to your specific needs. These can be found in the folder "/anarq/data/emails/".

You can see a complete example configuration file below.

{
  "anarq": {
    "frontend": {
      "url": "https://anarq.org"
    },
    "cooldown-minues": 15
  },
  "magic": {
    "smtp": {
      "host": "smtp.sendgrid.net",
      "port": 465,
      "secure": true,
      "username": "apikey",
      "password": "SG.dsf345asddfguh345.dsfouhg435ysSDFtrDFGsdf",
      "from": {
        "name": "John Doe",
        "address": "john@doe.com"
      }
    },
    "paypal": {
      "clientId": "AYXmWWv-OKV_RFjcksDoK4nJ0djwlhCmXp0h9staoD4U9dsY0oKfw8PBPH9TJ68s0SHjqGzWJNOT0inv",
      "allowDonations": "true"
    },
    "databases": {
      "mysql": {
        "generic": "Server=db;Database={database};Uid=root;Pwd=ThisIsNotAGoodPassword;SslMode=Preferred;Old Guids=true;"
      },
      "mssql": {
        "generic": "Server=localhost\\SQLEXPRESS;Database={database};Trusted_Connection=True;"
      },
      "default": "mysql"
    },
    "auth": {
      "secret": "asdfoih234gefhdudfu345o3i4uhfsduofdshou345togyguSDFGDSAHsadfoug435",
      "https-only": false,
      "valid-minutes": 120,
      "registration": {
        "allow": true,
        "confirm-email": null
      }
    },
    "io": {
      "root-folder": "~/files/"
    },
    "endpoint": {
      "root-folder": "~/files/"
    },
    "license": "TRIAL-VERSION"
  }
}

The things you'll need to change in the above configuration file is as follows.

  • magic/auth/secret - You'll need a new JWT auth secret
  • magic/paypal/clientId - You'll need to provide your own PayPal ClientID here
  • magic/smtp/password - If you're using SendGrid to send emails you can use your own API key password here
  • anarq/frontend/url - You'll need to provide the domain for where you intend to install AnarQ here

However, if you change the above parts, you can use the above appSettings.json file as is as you configure Magic. This allows you to use the Docker images for Magic, making installation of the backend extremely simple.

Also you'll need a licence of Magic before 47 hours, or the backend will stop working.

You can see a complete Angular HTTP service layer below, if you want to use AnarQ to learn Angular. This file wraps ever single HTTP endpoint and the AnarQ backend, and you are free to use it as you see fit.

Profile

This section contains everything related to authentication, registration, and public retrieval of profiles for registered users in the system.

GET magic/modules/anarq/profile/authenticate

This endpoint allows you to authenticate a user with a username/password combination, provided as URL encoded QUERY parameters. Below is an example.

https://your-api-domain.com/magic/modules/anarq/profile/authenticate?username=foo4&password=bar

The above will return a JWT token back to the caller, without an expiration date, or more specifically an expiration date 5 years into the future. This allows you to store the token in your client's persistent storage, such as for instance localStorage in your browser, and use the token to authorize future requests towards your backend. Each consecutive request on behalf of the user needs to associate this token in the HTTP Authorization header as a "Bearer" token. Below is an example

Authorization: Bearer eyJhbGciOixyz.eyJ1bmlxyz.GAP-Aluxyz

The token returned will not expire before 5 years into the future, allowing you to create clients where you don't store usernames and passwords, but rather simply store the token once as the user logs in, for never again to ask the user for a password again, before 5 years down the road of course.

This endpoint does not require the user to be authenticated.

POST magic/modules/anarq/profile/register

This endpoint registers a new user in the system. It takes the following payload.

{
  "username": "username_on_site",
  "password": "password_on_site",
  "email": "john@doe.com",
  "full_name": "John Doe",
  "email-type": "web|client"
}

If the username or email address is already registered on the site, the endpoint will return failure, explaining you more or less exactly what went wrong.

Notice, the exact flow of the registration process depends upon what client type you choose to use in the optional email-type in the payload you choose to create as you invoke endpoint. This field can have two different values.

  • web
  • client

The default value for email-type if omitted is web.

Web frontends

The value of web implies you have a web based HTML frontend somewhere, to where you can lead users, somehow resolving to a URL that will invoke the confirm-email endpoint as the user visits it, being able to retrieve the secret from a QUERY parameter named secret. Typically a link generated this way will look like the following.

https://your-frontend-domain.com/confirm-email?email=john%40doe.com&secret=345fbacd678e3eed11f

Once the user visits the above link in your frontend, you'll need to extract both the email and the secret QUERY parameters, and transmit these to the confirm-email endpoint, to have the user verify his or her email address.

The system will attempt to send an email to the registered email address, using configuration settings found from your configuration file, allowing the user to confirm his email address. If you wish to edit this template email, you can find it in "/anarq/data/emails/confirm-email.web.txt". In order to send a valid email, you need to configure your appSettings.json file having a value of anarq/frontend/url pointing to your frontend's root URL page, and you'll need to have a frontend URL being /confirm-email, accepting the following query parameters.

  • email
  • secret

The secret needs to be supplied to the profile/confirm-email endpoint later before the user can post, comment or like posts/comments in the system.

This endpoint does not require the user to be authenticated.

Client frontends

If you don't have a web based HTML capable frontend, due to maybe creating only an iOS or Android client - Then sending the user a hyperlink he clicks to confirm his email is obviously not a choice. Hence, you can therefor use the client type of email sent during registrations, which simply sends the user the generated secret, allowing him to copy and paste it into your app/client, for then to submit it to your backend somehow, by invoking the profile/confirm-email endpoint from within your client app.

GET magic/modules/anarq/profile/username-available

This endpoint returns true if the specified username is available. An example invocation can be found below.

https://your-api-domain.com/magic/modules/anarq/profile/username-available?username=foo3

If the username is registered from before, the above will result in the following result.

{
  "result": false,
  "message": "Username already registered"
}

If the username is available, the above result field will have a value of true.

This endpoint does not require the user to be authenticated. The idea is to invoke this endpoint as the user types his or her username, to check if the username is available or not, before clicking the "Register" button.

GET magic/modules/anarq/profile/email-available

This endpoint works exactly as the above username-available endpoint, except it of course expects an email query parameter, and checks to see if the specified email address is registered from before. If the email address is already registered from before, it will return something resembling the following.

{
  "result": false,
  "message": "Email address already registered"
}

If the email address is available, the above result field will have a value of true.

This endpoint does not require the user to be authenticated.

POST magic/modules/anarq/profile/confirm-email

This endpoints confirms a previously registered email address in the system, allowing the registered user to prove he owns the email address specified as he or she registered at the site. An example payload can be found below.

{
  "email": "john@doe.com",
  "secret": "SOME_SECRET_HASH_VALUE_HERE"
}

The secret above needs to be the secret generated automatically by the system as the user registered on the site, and is the SHA256 value of the combination of the user's email address, and the JWT auth secret in your appSettings.json configuration file.

This endpoint does not require the user to be authenticated.

GET magic/modules/anarq/profile/me

This endpoint returns information about the currently authenticated user, and can be used to retrieve meta data about the currently logged in user, such as his username, email, full name, roles, etc. This endpoint requires the user to be authenticated, and only returns information about the currently authenticated user. Kind of similar to whoami on a Linux system.

PUT magic/modules/anarq/profile/paypal-id

Stores the user's PayPal Client id, allowing user to get PayPal donations for his writing. Example payload below.

{
  "payPalId": "PayPal Client ID goes here ..."
}

PUT magic/modules/anarq/profile/email-notifications

Stores the user's email notifications settings. Implying whether or not AnarQ should send the user an email when something of interest occurs that the user should be notified about. Example payload below.

{
  "notifications": true
}

Posts

This section contains everything related to retrieving OP posts from the backend, in addition to the feeds, and some of the "gaming parts" of the system.

Notice, posts cannot contain HTML, but assuming your client can handle it, Markdown is perfectly safe. The backend will validate content submitted as the user tries to create or update a post, and if it contains illegal HTML characters, it will reject the insert/update, to avoid compromising other users by tricking them into downloading malicious JavaScript snippets, or HTML snippets that might contain malware of some sort.

GET magic/modules/anarq/posts/feed

Returns the most popular items according to the specified query parameters supplied. Popular here meaning items having the most likes. The endpoint takes 5 QUERY parameters, all of which are optional, and can be ommitted. Below is a list of parameters the endpoint can handle.

  • limit - Maximum number of posts to return. If specified this must be in between the range of 0-100. The default value if omitted is 25.
  • offset - Offset from where to start retrieving items. Combined with the above limit argument, this allows you to page items as you see fit.
  • topic - Name of topic to return items from within. See sub section topic for an explanation of this.
  • username - User that posted the OP.
  • minutes - Number of minutes to filter by. Notice, can be multiplied with e.g. 86,400 to filter according to days, weeks, etc.

This is the main "feed" endpoint, returning the most popular posts, according to what posts had the most upvotes. It allows you to filter posts only submitted by a specific user, or posts submitted within a specific topic. The minutes filter allows you to only return posts that were posted during the last n minutes, resulting in that old posts "drops off" the feed over time, regardless of how many upvotes they have. Which allows you to create feeds with most popular posts over the last 24 hours, 72 hours, etc as you see fit.

The endpoint will return something resembling the following.

[
  {
    "id": 3,
    "topic": "news",
    "created": "2021-03-09T08:50:17.000Z",
    "user": "john",
    "visibility": "protected",
    "excerpt": "Covid19 proven to be an international media hoax",
    "licks": 54
  },
  {
    "id": 1,
    "topic": "general",
    "created": "2021-03-09T08:21:46.000Z",
    "user": "peter",
    "visibility": "public",
    "excerpt": "Socially distancing you increases fatality rates for later mutations",
    "licks": 37
  },
]

Notice, the endpoint does not return the actual contents of the posts, only an excerpt including its first 50 characters. If you want to retrieve the entire content of a post, you'll have to use the GET posts/post invocation instead.

GET magic/modules/anarq/posts/post

This endpoint returns a single post, including its entire content, and number of likes it currently has. It takes one single QUERY parameter being the id of the post to return. Invoking it with the following URL ...

https://your-api-domain.com/magic/modules/anarq/posts/post?id=3

... might return something resembling the following.

{
  "id": 3,
  "topic": "news",
  "created": "2021-03-09T08:50:17.000Z",
  "user": "root",
  "visibility": "protected",
  "content": "This is ANOTHER news OP posting",
  "likes": 1
}

Notice, only authenticated users having confirmed their email address can retrieve posts that has "protected" as their visibility setting. Posts that have been moderated will only be returned to users belonging to one of the following roles.

  • root
  • admin
  • moderator

All other users can only see posts that are either "public" or "protected". Protected implies only visible for registered users at the site, having confirmed their email address. In addition, there is a status value for deleted posts being "deleted".

POST magic/modules/anarq/posts/post

This endpoint creates a new OP post, and requires the user to be authenticated, and having confirmed his email address. It takes the following payload.

{
  "visibility": "public",
  "topic": "news",
  "content": "Actual content of your post. Can contain Markdown but NOT HTML",
  "hyperlink": "https://foo.bar.com"
}

The visibility parts above must be one of the pre-defined visibility settings that exists in the system, typically one of the following values.

  • public
  • protected

Public posts are visible to anyone, including users just passing by as visitors, not being authenticated. Protected posts are only for users that have registered on the site, and having confirmed their email address. The endpoint will return the ID of the item created, allowing you to for instance instantly navigate to the item, or somehow show it to the user as it is created.

PUT magic/modules/anarq/posts/post

This endpoint updates an existing post, but can only be invoked by the user that originally created the post, and exists such that users can edit their existing posts, after having saved them. An example payload can be found below.

{
  "id": 67777,
  "content": "This is the new updated content of the post, and will overwrite existing content",
  "visibility": "public",
  "topic": "news",
  "hyperlink": "https://foo.bar.com"
}

A user can change both the content of the post, and the visibility of the post using this endpoint.

DELETE magic/modules/anarq/posts/post

Deletes a previously created OP post. Notice, endpoint can only be invoked by the user that originally created the OP post. And the post is not actually deleted, but only flagged as deleted, making it publicly invisible on the site for everyone except root accounts, admin accounts, and moderator accounts.

GET magic/modules/anarq/posts/posts-count

This endpoint returns the number of OP posts in the system. If invoked by an authenticated user having confirmed his or her email address, the endpoint will return count of both public and protected posts given the specified filtering conditions. If invoked by a visitor not authenticated, it will only return count of public posts. If invoked by a moderator, admin or root account, it will return count of all posts, including moderated posts.

The endpoint takes the following optional filtering conditions.

  • topic - Only show posts from within the specified topic
  • user - Only show posts created by the specified user

GET magic/modules/anarq/posts/posts

This endpoint works similarly to the above posts/feed endpoint, except it will not sort by popularity, but rather when the post was created. This allows you to retrieve all posts in the system, and page through them as you see fit, sorted by when the posts were created.

Notice, the endpoint will only return public posts unless invoked by an authenticated user having confirmed his or her email address, at which point the endpoint will also return protected posts. If invoked by a moderator, admin, or root account, the endpoint will return also moderated posts. Arguments for the endpoint are as follows, all arguments are optional.

  • topic
  • username
  • limit
  • offset

Comments

This section contains everything related to comments. Comments are stored as materialised paths, allowing you to build tree structures of comments in your frontend, to show comments as children of other comments, according to how they are created. This can be accomplished by using the "parent" field, and/or the "path" field returned by the endpoints used to retrieve comments.

Notice, comments cannot contain HTML, but assuming your client can handle it, Markdown is perfectly safe. The backend will validate content submitted as the user tries to create or update a comment, and if it contains illegal HTML characters, it will reject the insert/update, to avoid compromising other users by tricking them into downloading malicious JavaScript snippets, or HTML snippets that might contain malware of some sort.

POST magic/modules/anarq/comments/comment

This endpoint allows you to post a comment to either an OP posting, or another comment. Its payload is as follows.

{
  "parent": 67777,
  "content": "Actual content of comment. Can include Markdown but not HTML.",
  "visibility": "public"
}

The visibility of comments are similar to the visibility of OP posts, implying unless you've authenticated at the site, and confirmed your email address, only public posts will be visible for you. The parent above is the ID of the OP posting or another comment.

PUT magic/modules/anarq/comments/comment

This endpoint allows a user to edit his existing comment, either changing its visibility, and/or changing its content. It can only be invoked by the user creating the comment. An example payload can be found below.

{
  "id": 67777,
  "content": "Some new comment here. May include Markdown but not HTML.",
  "visibility": "public"
}

The endpoint works similarly to the POST equivalent above, except of course instead of taking a parent it requires an id to a previously created comment, and the comment must have been created by the same authenticated user trying to update it.

DELETE magic/modules/anarq/comments/comment

This endpoint works similarly to the above PUt equivalent, but instead of changing its visibility, and/or content, it marks the comment as deleted. The endpoint can only be invoked by the user originally having created the comment. The endpoint requires a single QUERY parameter, being the id of the post the caller wants to delete.

GET magic/modules/anarq/comments/comments

This endpoint returns comments belonging to a parent OP. It can take the following arguments.

  • parent - Parent OP post
  • limit - Maximum comments to return
  • offset - Offset of where to start returning comments

It will return something resembling the following.

[
  {
    "id":70,
    "created":"2021-03-25T08:09:28.000Z",
    "user":"thomas",
    "path":"/000000067/000000070",
    "parent":67,
    "content":"sefpih dfsgoih dfgoih dfg",
    "visibility":"public",
    "licks":0
  }
]

GET magic/modules/anarq/comments/comments-count

This endpoint returns the number of comments matching the specified arguments. Legal arguments are as follows.

  • topic - Topic to filter within
  • username - Username to filter within

Licks

This section contains endpoints for liking posts and comments, allowing users to like, and/or unlike existing posts, comments, etc.

POST magic/modules/anarq/licks/lick

Creates a like for an OP posting or a comment. The like will automatically be asssociated with the currently authenticated user. It requires the id to which post or comment you want to associate the like with. Each comment and post can only be likes by each user at most once. Below is an example payload.

{
  "id": 67777
}

DELETE magic/modules/anarq/licks/lick

Deletes a previously created like for either an OP post or a comment. The endpoint can only be invoked by a user having previously liked a comment or an OP post. The endpoint requires one single QUERY parameter being id, which is the ID for the comment, and/or post the user previously liked.

GET magic/modules/anarq/licks/likers

Returns all usernames for all users that liked a specific comment or an OP posting as an array of strings.

Topics

This section contains everything related to managing and administrating topics in the system.

POST magic/modules/anarq/topics/topic

This will create a new topic in your site, and takes a payload resembling the following.

{
  "name": "topic_name",
  "description": "This is the descriptive text explaining what your topic is about"
}

Name being the primary key for your topic.

PUT magic/modules/anarq/topics/topic

This will update the description of an existing topic. Notice, you cannot update the name after creating your topic, only its description. It requires a payload resembling the following.

{
  "name": "foo",
  "description": "This is the NEW descriptive text explaining what your topic is about"
}

DELETE magic/modules/anarq/topics/topic

This will delete an existing topic in the system. Notice, the topic cannot have any posts, or the deletion will fail. It takes one single parameter, being the name of the topic.

GET magic/modules/anarq/topics/topics

Returns all topics that exists in the system, together with how many posts topic has, and when the last activity within the topic was. Notice, this endpoint is cached, but there's another endpoint that is not cached.

GET magic/modules/anarq/topics/topics-no-cache

Returns all topics that exists in the system, together with how many posts topic has, and when the last activity within the topic was. Notice, this endpoint is not cached.

Admin

This section contains parts needed to administrate your backend, such as moderating posts or comments, blocking users, etc.

DELETE magic/modules/anarq/admin/comment

This endpoint allows you to hard delete a comment. Notice, the endpoint can only be invoked by a root or an admin account, and physically deletes the comment from your database. As an alternative, you might consider simply invoking the moderate endpoint, which only marks the post or comment as moderated instead of physically deleting it from your database. The endpoint takes one QUERY parameter named id, being the id of the comment you want to delete.

Warning - Deleting a comment will also recursively delete all descendant comments beneath the comment you're currently deleting, while moderating a comment will keep all descendant comments.

DELETE magic/modules/anarq/admin/post

This endpoint will perform a hard delete of an OP post from your database, and requires one QUERY parameter named id. The endpoint can only be invoked by an administrator.

DELETE magic/modules/anarq/admin/moderate-comment

This endpoint will moderate a comment, making it invisible on the site, but keep the actual data in your database, only performing a "soft delete". The endpoint requires one QUERY parameter named id, being the ID to the comment you wish to moderate.

DELETE magic/modules/anarq/admin/moderate-post

This endpoint will moderate an OP post, making it invisible on the site, but keep the actual data in your database, only performing a "soft delete". The endpoint requires one QUERY parameter named id, being the ID to the comment you wish to moderate.

DELETE magic/modules/anarq/admin/un-moderate-comment

This endpoint will un-moderate a comment, making it visible on the site. The endpoint requires one QUERY parameter named id, being the ID to the comment you wish to moderate.

DELETE magic/modules/anarq/admin/un-moderate-post

This endpoint will un-moderate an OP post, making it visible on the site. The endpoint requires one QUERY parameter named id, being the ID to the comment you wish to moderate.

DELETE magic/modules/anarq/admin/block-user

This endpoint will completely block a user from being able to interact with the backend. It requires one QUERY parameter being the username of the user you want to block. Endpoint can only be invoked by an admin of the site.

DELETE magic/modules/anarq/admin/un-block-user

This endpoint will remove a block on a user from the backend. It requires one QUERY parameter being the username of the user you want to un-block. Endpoint can only be invoked by an admin of the site.

User

This section allows you to admininstrate your users, and retreieve meta information associated with users.

GET magic/modules/anarq/users/user

This endpoint returns profile information for the specified username QUERY parameter. The returned response might resemble the following.

{
  "comments": 5,
  "created": "2021-03-09T14:14:30.000Z",
  "full_name": "Thomas Hansen",
  "karma": 7,
  "licks": 14,
  "locked": false,
  "posts": 21,
  "roles": [
    "guest",
    "root"
  ]
}

GET magic/modules/anarq/users/users

This endpoint lists all users matching the specified QUERY parameters. Parameters you can use are as follows.

  • limit
  • offset

GET magic/modules/anarq/users/users-count

Returns the number of registered users in the system.

Misc

These are miscelaneous endpoints, for things not specific to any of the above sections.

GET magic/modules/anarq/misc/donations

Returns true if donations have been turned on for site in general.

POST magic/modules/anarq/misc/log-donation

Logs a donation in the backend. Requires 3 QUERY parameters.

  • user - User that received the donation
  • donator - Email address of person donating
  • amount - Amount that was donated

GET magic/modules/anarq/misc/paypal-configuration

Returns site wide PayPal configuration. Notice, this is sitewide configuration, and not for individual users. It will return the PayPal ClientID associated with the site.

GET magic/modules/anarq/misc/tnc

Returns Terms and Conditions for the site. This is a Markdown document you can find within the folder structure of AnarQ module in the backend.

License

AnarQ is licensed under the terms of the MIT license, but you will need a license of Magic to run it.