Overview

Goodmorning Services contains the api stuff, manages various accounts, storage related things.

Api structure

Structured similar to a REST api, all paths can be found in /api/[service]/vX/[path...].

Some requires posts requests, some get requests, and sometimes multipart post if the client is trying to upload a file.

Requirements

To run this, use cargo r (--release):

  • Edit the autogenerated config files in (root) ~/.config/gm/
  • Have mongodb running as specified in storage.yml.

If you are using this as a dependency (such as gmt-server):

  • Run goodmorning_services::init() at the beginning.

Note that other more specialised servers may have additional API endpoints.

Bindings

Accounts

/api/accounts

Account operations such as create, delete, login.

v1

/api/accounts/v1

POST /api/accounts/v1/create


Create an account

Request

{
  "username": String,
  "email": String,
  "password": String
}

Response

Status code: 201

{
  "type": "created",
  "id": i64,
  "token": String,
  "verify": Boolean
}

Possible errors

  • invalid username
  • username taken
  • email taken
  • external

POST /api/accounts/v1/delete


Delete an account

Request

{
  "password": String,
  "token": String
}

Response

Status code: 200

{
  "type": "deleted"
}

Possible errors

  • invalid token
  • password incorrect
  • external

POST /api/accounts/v1/login


Get user ID and token from identifier and password.

Request

{
  "identifier": String,
  "identifier-type": "id"/"username"/"email",
  "password": String
}

Response

Status code: 200

{
  "type": "login",
  "id": i64,
  "token": String
}

Possible errors

  • no such user
  • password incorrect
  • external

POST /api/accounts/v1/regeneratetoken


Regenerate your token, invalidating all other logins.

Request

{
  "token": String,
  "password": String
}

Response

Status code: 200

{
  "type": "regenerated",
  "token": String
}

Possible errors

  • invalid token
  • password incorrect
  • external

POST /api/accounts/v1/rename


Change username.

Request

{
  "token": String,
  "new": String
}

Response

Status code: 200

{
  "type": "renamed"
}

Possible errors

  • invalid username
  • invalid token
  • password incorrect
  • external

POST /api/accounts/v1/change-password


Regenerate your token, invalidating all other logins.

Request

{
  "new": String, // the password you want to change to
  "old": String,
  "token": String
}

Response

Status code: 200

{
  "type": "password changed"
}

Possible errors

  • password incorrect
  • invalid token
  • external

POST /api/accounts/v1/change-email


Regenerate your token, invalidating all other logins.

Request

{
  "new": String, // the email you want to change to
  "token": String,
  "password": String
}

Response

Status code: 200

{
  "type": "email changed",
  "verify": Boolean
}

Possible errors

  • email taken
  • password incorrect
  • invalid token
  • cooldown
  • external

POST /api/accounts/v1/resend-verify


Resend verification message to email.

Request

{
  "token": String
}

Response

Status code: 200

{
  "type": "verification sent"
}

Possible errors

  • invalid token
  • nothing changed
  • cooldown
  • external

POST /api/accounts/v1/set-status


Change user status.

Request

{
  "token": String,
  "new": String
}

Response

Status code: 200

{
  "type": "profile updated"
}

Possible errors

  • invalid token
  • exceeds maximum length
  • external

POST /api/accounts/v1/access


View users with this access.

Request

{
  "token": String,
  "access_type": AccessType,
  "identifier": String?,
  "identifier-type": String?
}

AccessType includes file, blue, and access.

Response

Status code: 200

{
  "type": "access",
  "users": [
    {
      "id": Int,
      "name": String
    }
    // ...
  ]
}

Possible errors

  • no such user
  • invalid token
  • permission denied
  • external

POST /api/accounts/v1/accessto


View users with this user have access to.

Request

{
  "token": String,
  "access_type": AccessType,
  "identifier": String?,
  "identifier-type": String?
}

AccessType includes file, blue, and access.

Response

Status code: 200

{
  "type": "allowed access",
  "users": [
    {
      "id": Int,
      "name": String
    }
    // ...
  ]
}

Possible errors

  • no such user
  • invalid token
  • permission denied
  • external

POST /api/accounts/v1/allow


Allow access for a user.

Request

{
  "token": String,
  "identifier": String,
  "identifier-type": "id"/"username"/"email",
  "access_type": AccessType
}

Response

Status code: 200

{
  "type": "allowed"
}

Possible errors

  • no such user
  • invalid token
  • external

POST /api/accounts/v1/disallow


Remove access for a user.

Request

{
  "token": String,
  "identifier": String,
  "identifier-type": "id"/"username"/"email",
  "access_type": AccessType
}

Response

Status code: 200

{
  "type": "disallowed"
}

Possible errors

  • no such user
  • invalid token
  • external

Storage

/api/storage

User storage operations such as copy, upload, ls.

v1

/api/storage/v1

POST /api/storage/v1/copy or /api/storage/v1/copy-overwrite


Copy file to destination path, file can be owned by self or by others (only if the file is hidden or public).

Request

{
  "token": String,
  "from-userid": i64, (who to copy from, can be your own id)
  "from": String,
  "to": String
}

Response

Status code: 201

{
  "type": "copied"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • path occupied (non overwrite only)
  • file not found
  • storage full
  • external

POST /api/storage/v1/delete


Delete file.

Request

{
  "token": String,
  "path": String
}

Response

Status code: 200

{
  "type": "deleted"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • external

POST /api/storage/v1/delete-multiple


Delete multiple file in order.

Request

{
  "token": String,
  "paths": [String]
}

Response

Status code: 200

{
  "type": "multi",
  "res": [V1Response]
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • external

POST /api/storage/v1/exists


Check if file exists

Request

{
  "token": String,
  "path": String
}

Response

Status code: 200

{
  "type": "exists",
  "value": bool
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • external

GET /api/storage/v1/diritems/[token]/[path]


List items in directory.

For example to access /dir/deeper in your storage, you GET /api/storage/v1/diritems/token-gibberish/dir/deeper, where /dir/deeper is a directory.

Response

Status code: 200

{
  "type": "dir content",
  "content": [
    {
      "visibility": {
        "inherited": bool,
        "visibility": "hidden"/"private"/"public"
      },
      "is_file": bool,
      "name": String,
      "last_modified": u64,
      "size": u64
    },
    ...
  ]
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • type mismatch
  • external

GET /api/storage/v1/tree/[token]/[path]


Tree items in directory.

Response

Status code: 200

{
  "type": "tree",
  "content": TreeNode
}

Where TreeNode can either be a directory:

{
  "type": "dir",
  "name": String,
  "visibility": {
    "inherited": bool,
    "visibility": Visibility // public, hidden or private
  }
}

or a file:

{
  "type": "file",
  "name": String,
  "size": u64,
  "last_modified": u64,
  "visibility": {
    "inherited": bool,
    "visibility": Visibility,
  }
}

For example

{
  "type": "tree",
  "content": {
    "type": "dir",
    "name": ".system",
    "visibility": {
      "inherited": true,
      "visibility": public,
    },
    "content": [
      {
        "type": "file",
        "name": "pfp.png",
        "size": 1165233,
        "last_modified": 1688643521,
        "visibility": {
          "inherited": true,
          "visibility": "public",
        }
      }
    ]
  }
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • type mismatch
  • external

GET /api/storage/v1/file/[token]/[path]


Returns file content.

For example to access /dir/file.txt in your storage, you GET /api/storage/v1/diritems/token-gibberish/dir/file.txt, where /dir/file.txt is a file.

Response

Status code: 200

[file content]

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • type mismatch
  • external

POST /api/storage/v1/mkdir


Creates a directory

Request

{
  "token": String,
  "path": String
}

Response

Status code: 201

{
  "type": "file item created"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • external

POST /api/storage/v1/mkdir-multiple


Creates multiple directories in order

Request

{
  "token": String,
  "paths": [String]
}

Response

Status code: 201

{
  "type": "multi",
  "res": [V1Response]
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • external

POST /api/storage/v1/move or /api/storage/v1/move-overwrite or /api/storage/v1/move-createdirs or /api/storage/v1/move-createdirs-overwrite


Move/rename file to destination path.

Request

{
  "token": String,
  "from": String,
  "to": String
}

Response

Status code: 200

{
  "type": "moved"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • path occupied (non overwrite only)
  • file not found
  • external

POST /api/storage/v1/set-visibility or /api/storage/v1/remove-visibility


Change file or directory visibility.

Request (set)

{
  "token": String,
  "path": String,
  "visibility": "hidden"/"private"/"public"
}

Request (remove)

{
  "token": String,
  "path": String,
}

Response

Status code: 200

{
  "type": "visibility changed"
}

or

Status code: 304

{
  "type": "nothing changed"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • file not found
  • external

POST /api/storage/v1/touch


Creates an empty file.

Request

{
  "token": String,
  "path": String
}

Response

Status code: 201

{
  "type": "file item created"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • external

POST with multipart /api/storage/v1/upload/[token]/[path], /api/storage/v1/upload-createdirs/[token]/[path], /api/storage/v1/upload-overwrite/[token]/[path] and /api/storage/v1/upload-createdirs-overwrite/[token]/[path]


Upload a file to destination path.

  • upload returns an error if the directory the file is uploading to does not exist, or the file path is occupied.
  • upload-overwrite overwrites whatever is in the path.
  • upload-createdirs create parent directory for the upload target if it does not exist.
  • upload-createdirs-overwrite a mix of both

Request

[multipart file post]

Response

Status code: 201

{
  "type": "file item created"
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • path occupied (non overwrite only)
  • file not found
  • storage full
  • external

Usercontent

/api/usercontent

View files created by other users.

v1

/api/usercontent/v1

GET /api/usercontent/v1/exists/id/[id]/[path]


Check if file exists

Response

Status code: 200

{
  "type": "exists",
  "value": bool
}

Possible errors

  • invalid token
  • not verified
  • permission denied
  • external

GET /api/usercontent/v1/diritems/id/[userid]/[path]


List items in directory.

For example to access /dir/deeper in user with ID 1's storage, you GET /api/usercontent/v1/diritems/1/dir/deeper, where /dir/deeper is a directory.

Response

Status code: 200

{
  "type": "dir content",
  "content": [
    {
      "visibility": {
        "inherited": bool,
        "visibility": "hidden"/"private"/"public"
      },
      "is_file": bool,
      "name": String,
      "last_modified": u64,
      "size": u64
    },
    ...
  ]
}

Possible errors

  • permission denied
  • file not found
  • type mismatch
  • external

GET /api/usercontent/v1/tree/id/[userid]/[path]


Tree items in directory.

Response

Status code: 200

{
  "type": "tree",
  "content": TreeNode
}

Where TreeNode can either be a directory:

{
  "type": "dir",
  "name": String,
  "visibility": {
    "inherited": bool,
    "visibility": Visibility // public, hidden or private
  }
}

or a file:

{
  "type": "file",
  "name": String,
  "size": u64,
  "last_modified": u64,
  "visibility": {
    "inherited": bool,
    "visibility": Visibility,
  }
}

For example

{
  "type": "tree",
  "content": {
    "type": "dir",
    "name": ".system",
    "visibility": {
      "inherited": true,
      "visibility": public,
    },
    "content": [
      {
        "type": "file",
        "name": "pfp.png",
        "size": 1165233,
        "last_modified": 1688643521,
        "visibility": {
          "inherited": true,
          "visibility": "public",
        }
      }
    ]
  }
}

Possible errors

  • permission denied
  • file not found
  • type mismatch
  • external

GET /api/usercontent/v1/file/id/[userid]/[path]


Returns file content.

For example to access /dir/file.txt in user with ID 1's storage, you GET /api/usercontent/v1/file/id/1/dir/file.txt, where /dir/file.txt is a file.

Response

Status code: 200

[file content]

Possible errors

  • permission denied
  • file not found
  • type mismatch
  • external

Triggers

/api/triggers

Urls that run trigger functions.

v1

/api/triggers/v1

GET /api/triggers/v1/use/[trigger id]


Uses trigger - and runs the code.

Response

Status code: 200

{
  "type": "triggered"
}

Possible errors

  • trigger not found
  • external

GET /api/triggers/v1/use/[trigger id]


Revokes trigger so it can no longer be used.

Response

Status code: 200

{
  "type": "revoked"
}

Possible errors

  • trigger not found
  • external

GET /api/triggers/v1/peek/[trigger id]


View trigger content without triggering it.

Response

Status code: 200

{
  "type": "trigger peak",
  "value": {
    "type": "...",
    ...
  }
}

Possible errors

  • trigger not found
  • external

POST /api/jobs/v1/jobs


List queued and running jobs.

Request

{
  "token": String
}

Response

Status code: 200

{
  "type": "jobs",
  "current": [
    {
      "id": u64,
      "task": {
        "type": "compile",
        "from": FromFormat,
        "to": ToFormat,
        "compiler": Compiler,
        "path": String,
      }
    }
  ],
  "queue": [
    // ...
  ]
}

Possible errors

  • invalid token
  • external

POST /api/jobs/v1/unqueue


Remove a queued job

Request

{
  "token": String,
  "id": u64
}

Response

Status code: 200

{
  "type": "unqueued"
}

Possible errors

  • invalid token
  • external
  • job not found