Merge branch 'main' of gitlab.com:mstarongitlab/linstrom

This commit is contained in:
Melody Becker 2024-09-15 12:25:45 +02:00
commit 71beed7eb3
86 changed files with 34935 additions and 155 deletions

32
.gitignore vendored
View file

@ -3,6 +3,38 @@ db.sqlite
.env .env
.lapce/ .lapce/
*/tmp.* */tmp.*
<<<<<<< HEAD
/frontend/
# --- Section ember frontend ---
# compiled output
/frontend-src/dist/
/frontend-src/declarations/
# dependencies
/frontend-src/node_modules/
# misc
/frontend-src/.env*
/frontend-src/.pnp*
/frontend-src/.eslintcache
/frontend-src/coverage/
/frontend-src/npm-debug.log*
/frontend-src/testem.log
/frontend-src/yarn-error.log
# ember-try
/frontend-src/.node_modules.ember-try/
/frontend-src/npm-shrinkwrap.json.ember-try
/frontend-src/package.json.ember-try
/frontend-src/package-lock.json.ember-try
/frontend-src/yarn.lock.ember-try
# broccoli-debug
/frontend-src/DEBUG/
=======
config.toml config.toml
.air.toml .air.toml
>>>>>>> 0ec0ad42bca3a05b05256862904285bb74e314cb

26
Containerfile Normal file
View file

@ -0,0 +1,26 @@
FROM docker.io/node:22 AS build-ember
# TODO: Implement ember frontend build
FROM docker.io/golang:1.23 AS build-go
# TODO: Implement golang build
FROM gcr.io/distroless/static-debian12:latest as release
# TODO: Implement final release container
# OCI labels, following https://github.com/opencontainers/image-spec/blob/main/annotations.md
# Make this one dynamic
# LABEL org.opencontainers.image.created = rfc timestamp, according to https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
LABEL org.opencontainers.image.authors="Melody Becker/m*"
# LABEL org.opencontainers.image.url="Main linstrom page url here"
# LABEL org.opencontainers.image.documentation="Url to main linstrom documentation here"
LABEL org.opencontainers.image.source="https://gitlab.com/mstarongitlab/linstrom"
# Make this one dynamic from build tag
LABEL org.opencontainers.image.version="0.0.1"
# LABEL org.opencontainers.image.revision="idk what"
# LABEL org.opencontainers.image.vendor="None/m*"
LABEL org.opencontainers.image.licenses="EUPL-1.2"
# LABEL org.opencontainers.image.ref.name="uhh, no idea either"
LABEL org.opencontainers.image.title="Linstrom"
LABEL org.opencontainers.image.description="A social media server acting as part of the fediverse"
# Make this automatic since latest distroless image gets update constantly
# LABEL org.opencontainers.image.base.digest="digest/hash of base image"
LABEL org.opencontainers.image.base.name="gcr.io/distroless/static-debian12:latest"

View file

@ -1,24 +0,0 @@
package ap
import "strings"
// Header used for making requests for AP resources
// Not used yet
const OUTBOUND_REQUEST_HEADER = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1"
var contentHeadersToCheck = []string{
"application/json",
"application/ld+json",
}
// Check a given string if it contains any of the content types specified in
// the contentHeadersToCheck slice
// Used for differentiating requests for the ActivityPub version of some data vs frontend version
func ContainsApContentHeader(toCheck string) bool {
for _, h := range contentHeadersToCheck {
if strings.Contains(toCheck, h) {
return true
}
}
return false
}

View file

@ -56,12 +56,25 @@ type ConfigStorage struct {
MaxInMemoryCacheSize int64 `toml:"max_in_memory_cache_size"` MaxInMemoryCacheSize int64 `toml:"max_in_memory_cache_size"`
} }
type ConfigMail struct {
Host string `toml:"host"`
Port int `toml:"port"`
Username string `toml:"username"`
Password string `toml:"password"`
EncryptionOverwrite *string `toml:"encryption_overwrite,omitempty"`
KeepAliveOverwrite *bool `toml:"keep_alive_overwrite,omitempty"`
ConnectTimeoutSecondsOverwrite *int `toml:"connect_timeout_seconds_overwrite,omitempty"`
SendTimeoutSecondsOverwrite *int `toml:"send_timeout_seconds_overwrite,omitempty"`
TemplateOverwriteDirectory *string `toml:"template_overwrite_directory,omitempty"`
}
type Config struct { type Config struct {
General ConfigGeneral `toml:"general"` General ConfigGeneral `toml:"general"`
SSL ConfigSSL `toml:"ssl"` SSL ConfigSSL `toml:"ssl"`
Admin ConfigAdmin `toml:"admin"` Admin ConfigAdmin `toml:"admin"`
Webauthn ConfigWebAuthn `toml:"webauthn"` Webauthn ConfigWebAuthn `toml:"webauthn"`
Storage ConfigStorage `toml:"storage"` Storage ConfigStorage `toml:"storage"`
Mail ConfigMail `toml:"mail"`
} }
var GlobalConfig Config var GlobalConfig Config

76
example_config.toml Normal file
View file

@ -0,0 +1,76 @@
# General information for the server, primarely domain and port
[general]
# The domain the server operates under
domain = "localhost"
# The full domain to connect to the server, excluding port
full_domain = "http://localhost"
# The port the server is accessed from by the public, usually 80 or 443
public_port = 8080
# The port the server actually operates under
# This is where for example nginx or Traeffik should connect to
private_port = 8080
# How the server should handle SSL (for https)
[ssl]
# Whether the server should handle SSL itself
# Recommended to be false if behind a reverse proxy like nginx or Traeffik
handle_ssl = false
# Required if handle_ssl is true
# Whether the server should use Lets Encrypt for getting the certificate
# use_lets_encrypt = true
# Required if use_lets_encrypt is false
# The certificate file to use for SSL
# certificate_file = some-certificate.pim
# Required if use_lets_encrypt is true
# The admin mail for Lets Encrypt to send certificate infos to
# admin_mail = "admin@example.com"
# Login details for the root admin account
[admin]
username = "admin"
# Empty password hash means no password set
# TODO: Include used hashing algorithm
password_hash = ""
# Where to find the db and what type it is
[storage]
# If the uri points to a postgres db or not (sqlite otherwise)
is_postgres = false
# The uri for the db. A filepath for sqlite, postgres url otherwise
uri = "db.sqlite"
# Details for the mail server to use for sending stuff
# TODO: Extend if server uses multiple accoutns later
[mail]
host = "smtp.example.com"
port = 587
username = "noreply@example.com"
password = "example"
# Overwrite the used encryption method
# Defaults to StartTLS
# TODO: Include all options here
# encryption_overwrite = "StartTLS"
# Overwrite whether the server should keep the connection alive constantly
# Default is false
# keep_alive_overwrite = false
# Overwrite the amount of seconds before the connection times out
# Default is 10
# connection_timeout_seconds_overwrite = 10
# Overwrite the amount of seconds before a mail send times out
# Default is 10
# send_timeout_seconds_overwrite = 10
# Overwrite the templates used for creating mails
# Defaults to built-in one if no matching name for an action is found
# TODO: Include all names for the various actions
# template_directory_overwrite = "templates"

7
featureTargets.md Normal file
View file

@ -0,0 +1,7 @@
- "Lockdown" mode per user or server-wide
- Lockdown means that incoming traffic will be entirely binned
- Optional scanning of notes and media for bad content using Microsoft's services
- Extendable to entire instances by checking their public feed for a bit
- ActivityPub bypass protocol
- AP is slow and really annoying to deal with
- Allows sharing metadata like link previews or scan results

@ -1 +0,0 @@
Subproject commit 94f7c146f67651d44c190163c8ac6312024dea90

View file

@ -0,0 +1,11 @@
<html>
<!--
TODO: Implement me
-->
<!--
Will contain templates for use in the no js frontend version
The no js frontend will be minimal and likely just barely usable, so not ever the default
-->
</html>

View file

@ -1,3 +0,0 @@
<html>
</html>

View file

@ -0,0 +1,19 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.hbs]
insert_final_newline = false
[*.{diff,md}]
trim_trailing_whitespace = false

7
frontend-src/.ember-cli Normal file
View file

@ -0,0 +1,7 @@
{
/**
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
*/
"isTypeScriptProject": true
}

View file

@ -0,0 +1,13 @@
# unconventional js
/blueprints/*/files/
# compiled output
/dist/
# misc
/coverage/
!.*
.*/
# ember-try
/.node_modules.ember-try/

55
frontend-src/.eslintrc.js Normal file
View file

@ -0,0 +1,55 @@
'use strict';
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
},
plugins: ['ember', '@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
env: {
browser: true,
},
rules: {},
overrides: [
// ts files
{
files: ['**/*.ts'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {},
},
// node files
{
files: [
'./.eslintrc.js',
'./.prettierrc.js',
'./.stylelintrc.js',
'./.template-lintrc.js',
'./ember-cli-build.js',
'./testem.js',
'./blueprints/*/index.js',
'./config/**/*.js',
'./lib/*/index.js',
'./server/**/*.js',
],
env: {
browser: false,
node: true,
},
extends: ['plugin:n/recommended'],
},
{
// test files
files: ['tests/**/*-test.{js,ts}'],
extends: ['plugin:qunit/recommended'],
},
],
};

47
frontend-src/.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: CI
on:
push:
branches:
- main
- master
pull_request: {}
concurrency:
group: ci-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
lint:
name: "Lint"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: npm
- name: Install Dependencies
run: npm ci
- name: Lint
run: npm run lint
test:
name: "Test"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: npm
- name: Install Dependencies
run: npm ci
- name: Run Tests
run: npm test

25
frontend-src/.gitignore vendored Normal file
View file

@ -0,0 +1,25 @@
# compiled output
/dist/
/declarations/
# dependencies
/node_modules/
# misc
/.env*
/.pnp*
/.eslintcache
/coverage/
/npm-debug.log*
/testem.log
/yarn-error.log
# ember-try
/.node_modules.ember-try/
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try
# broccoli-debug
/DEBUG/

View file

@ -0,0 +1,13 @@
# unconventional js
/blueprints/*/files/
# compiled output
/dist/
# misc
/coverage/
!.*
.*/
# ember-try
/.node_modules.ember-try/

View file

@ -0,0 +1,12 @@
'use strict';
module.exports = {
overrides: [
{
files: '*.{js,ts}',
options: {
singleQuote: true,
},
},
],
};

View file

@ -0,0 +1,8 @@
# unconventional files
/blueprints/*/files/
# compiled output
/dist/
# addons
/.node_modules.ember-try/

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'],
};

View file

@ -0,0 +1,5 @@
'use strict';
module.exports = {
extends: 'recommended',
};

View file

@ -0,0 +1,3 @@
{
"ignore_dirs": ["dist"]
}

56
frontend-src/README.md Normal file
View file

@ -0,0 +1,56 @@
# frontend-src
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
## Prerequisites
You will need the following things properly installed on your computer.
* [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/) (with npm)
* [Ember CLI](https://cli.emberjs.com/release/)
* [Google Chrome](https://google.com/chrome/)
## Installation
* `git clone <repository-url>` this repository
* `cd frontend-src`
* `npm install`
## Running / Development
* `npm run start`
* Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
### Code Generators
Make use of the many generators for code, try `ember help generate` for more details
### Running Tests
* `npm run test`
* `npm run test:ember -- --server`
### Linting
* `npm run lint`
* `npm run lint:fix`
### Building
* `npm exec ember build` (development)
* `npm run build` (production)
### Deploying
Specify what it takes to deploy your app.
## Further Reading / Useful Links
* [ember.js](https://emberjs.com/)
* [ember-cli](https://cli.emberjs.com/release/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)

12
frontend-src/app/app.ts Normal file
View file

@ -0,0 +1,12 @@
import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from 'frontend-src/config/environment';
export default class App extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
}
loadInitializers(App, config.modulePrefix);

View file

View file

@ -0,0 +1 @@
{{yield}}

View file

@ -0,0 +1,14 @@
import Component from '@glimmer/component';
export interface NoteSignature {
// The arguments accepted by the component
Args: {};
// Any blocks yielded by the component
Blocks: {
default: [];
};
// The element to which `...attributes` is applied in the component template
Element: null;
}
export default class NoteComponent extends Component<NoteSignature> {}

View file

@ -0,0 +1,14 @@
/**
* Type declarations for
* import config from 'frontend-src/config/environment'
*/
declare const config: {
environment: string;
modulePrefix: string;
podModulePrefix: string;
locationType: 'history' | 'hash' | 'none';
rootURL: string;
APP: Record<string, unknown>;
};
export default config;

View file

View file

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>FrontendSrc</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{content-for "head"}}
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/frontend-src.css">
{{content-for "head-footer"}}
</head>
<body>
{{content-for "body"}}
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/frontend-src.js"></script>
{{content-for "body-footer"}}
</body>
</html>

View file

View file

@ -0,0 +1,14 @@
import EmberRouter from '@ember/routing/router';
import config from 'frontend-src/config/environment';
export default class Router extends EmberRouter {
location = config.locationType;
rootURL = config.rootURL;
}
Router.map(function () {
this.route('notes', function () {
this.route('note', { path: '/:note_id' });
this.route('index', { path: '/' });
});
});

View file

View file

@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class NotesRoute extends Route {}

View file

@ -0,0 +1,3 @@
import Route from '@ember/routing/route';
export default class NotesIndexRoute extends Route {}

View file

@ -0,0 +1,9 @@
import Route from '@ember/routing/route';
import type Transition from '@ember/routing/transition';
export default class NotesNoteRoute extends Route {
model(params: any, transition: Transition) {
console.log(params);
return { title: params.note_id };
}
}

View file

@ -0,0 +1 @@
/* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */

View file

@ -0,0 +1,4 @@
{{page-title "FrontendSrc"}}
<h1>Home page</h1>
{{outlet}}

View file

@ -0,0 +1,3 @@
{{page-title "Notes"}}
<h2>Note wrapper</h2>
{{outlet}}

View file

@ -0,0 +1,4 @@
{{page-title "Index"}}
<h3>Note index</h3>
{{outlet}}

View file

@ -0,0 +1,4 @@
{{page-title "Note"}}
<h3>Note {{@model.title}}</h3>
{{outlet}}

View file

@ -0,0 +1,21 @@
{
"schemaVersion": "1.0.0",
"packages": [
{
"name": "ember-cli",
"version": "5.7.0",
"blueprints": [
{
"name": "app",
"outputRepo": "https://github.com/ember-cli/ember-new-output",
"codemodsSource": "ember-app-codemods-manifest@1",
"isBaseBlueprint": true,
"options": [
"--ci-provider=github",
"--typescript"
]
}
]
}
]
}

View file

@ -0,0 +1,48 @@
'use strict';
module.exports = function (environment) {
const ENV = {
modulePrefix: 'frontend-src',
environment,
rootURL: '/',
locationType: 'history',
EmberENV: {
EXTEND_PROTOTYPES: false,
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
},
},
APP: {
// Here you can pass flags/options to your application instance
// when it is created
},
};
if (environment === 'development') {
// ENV.APP.LOG_RESOLVER = true;
// ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true;
}
if (environment === 'test') {
// Testem prefers this...
ENV.locationType = 'none';
// keep test console output quieter
ENV.APP.LOG_ACTIVE_GENERATION = false;
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
}
if (environment === 'production') {
// here you can enable a production-specific feature
}
return ENV;
};

View file

@ -0,0 +1,7 @@
{
"application-template-wrapper": false,
"default-async-observers": true,
"jquery-integration": false,
"template-only-glimmer-components": true,
"no-implicit-route-model": true
}

View file

@ -0,0 +1,11 @@
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions',
];
module.exports = {
browsers,
};

View file

@ -0,0 +1,13 @@
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function (defaults) {
const app = new EmberApp(defaults, {
'ember-cli-babel': { enableTypeScriptTransform: true },
// Add options here
});
return app.toTree();
};

33765
frontend-src/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

113
frontend-src/package.json Normal file
View file

@ -0,0 +1,113 @@
{
"name": "frontend-src",
"version": "0.0.0",
"private": true,
"description": "Small description for frontend-src goes here",
"repository": "",
"license": "MIT",
"author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
"scripts": {
"build": "ember build --environment=production",
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:css": "stylelint \"**/*.css\"",
"lint:css:fix": "concurrently \"npm:lint:css -- --fix\"",
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
"lint:hbs": "ember-template-lint .",
"lint:hbs:fix": "ember-template-lint . --fix",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"lint:types": "tsc --noEmit",
"start": "ember serve",
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
"test:ember": "ember test"
},
"devDependencies": {
"@babel/core": "^7.24.0",
"@ember/optional-features": "^2.1.0",
"@ember/string": "^3.1.1",
"@ember/test-helpers": "^3.3.0",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"@glint/environment-ember-loose": "^1.3.0",
"@glint/template": "^1.3.0",
"@tsconfig/ember": "^3.0.4",
"@types/ember": "^4.0.11",
"@types/ember-data": "^4.4.16",
"@types/ember-data__adapter": "^4.0.6",
"@types/ember-data__model": "^4.0.5",
"@types/ember-data__serializer": "^4.0.6",
"@types/ember-data__store": "^4.0.7",
"@types/ember__application": "^4.0.11",
"@types/ember__array": "^4.0.10",
"@types/ember__component": "^4.0.22",
"@types/ember__controller": "^4.0.12",
"@types/ember__debug": "^4.0.8",
"@types/ember__destroyable": "^4.0.5",
"@types/ember__engine": "^4.0.11",
"@types/ember__error": "^4.0.6",
"@types/ember__helper": "^4.0.7",
"@types/ember__modifier": "^4.0.9",
"@types/ember__object": "^4.0.12",
"@types/ember__owner": "^4.0.9",
"@types/ember__polyfills": "^4.0.6",
"@types/ember__routing": "^4.0.22",
"@types/ember__runloop": "^4.0.10",
"@types/ember__service": "^4.0.9",
"@types/ember__string": "^3.16.3",
"@types/ember__template": "^4.0.7",
"@types/ember__test": "^4.0.6",
"@types/ember__utils": "^4.0.7",
"@types/qunit": "^2.19.10",
"@types/rsvp": "^4.0.9",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"broccoli-asset-rev": "^3.0.0",
"concurrently": "^8.2.2",
"ember-auto-import": "^2.7.2",
"ember-cli": "~5.7.0",
"ember-cli-app-version": "^6.0.1",
"ember-cli-babel": "^8.2.0",
"ember-cli-clean-css": "^3.0.0",
"ember-cli-dependency-checker": "^3.3.2",
"ember-cli-htmlbars": "^6.3.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-data": "~5.3.3",
"ember-fetch": "^8.1.2",
"ember-load-initializers": "^2.1.2",
"ember-modifier": "^4.1.0",
"ember-page-title": "^8.2.2",
"ember-qunit": "^8.0.2",
"ember-resolver": "^11.0.1",
"ember-source": "~5.7.0",
"ember-template-lint": "^5.13.0",
"ember-welcome-page": "^7.0.2",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-ember": "^11.12.0",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-qunit": "^8.1.1",
"loader.js": "^4.7.0",
"prettier": "^3.2.5",
"qunit": "^2.20.1",
"qunit-dom": "^2.0.0",
"stylelint": "^15.11.0",
"stylelint-config-standard": "^34.0.0",
"stylelint-prettier": "^4.1.0",
"tracked-built-ins": "^3.3.0",
"typescript": "^5.3.3",
"webpack": "^5.90.3"
},
"engines": {
"node": ">= 18"
},
"ember": {
"edition": "octane"
}
}

View file

@ -0,0 +1,3 @@
# http://www.robotstxt.org
User-agent: *
Disallow:

23
frontend-src/testem.js Normal file
View file

@ -0,0 +1,23 @@
'use strict';
module.exports = {
test_page: 'tests/index.html?hidepassed',
disable_watching: true,
launch_in_ci: ['Chrome'],
launch_in_dev: ['Chrome'],
browser_start_timeout: 120,
browser_args: {
Chrome: {
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null,
'--headless',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900',
].filter(Boolean),
},
},
};

View file

@ -0,0 +1,43 @@
import {
setupApplicationTest as upstreamSetupApplicationTest,
setupRenderingTest as upstreamSetupRenderingTest,
setupTest as upstreamSetupTest,
type SetupTestOptions,
} from 'ember-qunit';
// This file exists to provide wrappers around ember-qunit's
// test setup functions. This way, you can easily extend the setup that is
// needed per test type.
function setupApplicationTest(hooks: NestedHooks, options?: SetupTestOptions) {
upstreamSetupApplicationTest(hooks, options);
// Additional setup for application tests can be done here.
//
// For example, if you need an authenticated session for each
// application test, you could do:
//
// hooks.beforeEach(async function () {
// await authenticateSession(); // ember-simple-auth
// });
//
// This is also a good place to call test setup functions coming
// from other addons:
//
// setupIntl(hooks); // ember-intl
// setupMirage(hooks); // ember-cli-mirage
}
function setupRenderingTest(hooks: NestedHooks, options?: SetupTestOptions) {
upstreamSetupRenderingTest(hooks, options);
// Additional setup for rendering tests can be done here.
}
function setupTest(hooks: NestedHooks, options?: SetupTestOptions) {
upstreamSetupTest(hooks, options);
// Additional setup for unit tests can be done here.
}
export { setupApplicationTest, setupRenderingTest, setupTest };

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>FrontendSrc Tests</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{content-for "head"}}
{{content-for "test-head"}}
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link rel="stylesheet" href="{{rootURL}}assets/frontend-src.css">
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
{{content-for "head-footer"}}
{{content-for "test-head-footer"}}
</head>
<body>
{{content-for "body"}}
{{content-for "test-body"}}
<div id="qunit"></div>
<div id="qunit-fixture">
<div id="ember-testing-container">
<div id="ember-testing"></div>
</div>
</div>
<script src="/testem.js" integrity="" data-embroider-ignore></script>
<script src="{{rootURL}}assets/vendor.js"></script>
<script src="{{rootURL}}assets/test-support.js"></script>
<script src="{{rootURL}}assets/frontend-src.js"></script>
<script src="{{rootURL}}assets/tests.js"></script>
{{content-for "body-footer"}}
{{content-for "test-body-footer"}}
</body>
</html>

View file

View file

@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'frontend-src/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | note', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Note />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Note>
template block text
</Note>
`);
assert.dom().hasText('template block text');
});
});

View file

@ -0,0 +1,12 @@
import Application from 'frontend-src/app';
import config from 'frontend-src/config/environment';
import * as QUnit from 'qunit';
import { setApplication } from '@ember/test-helpers';
import { setup } from 'qunit-dom';
import { start } from 'ember-qunit';
setApplication(Application.create(config.APP));
setup(QUnit.assert);
start();

View file

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'frontend-src/tests/helpers';
module('Unit | Route | notes', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
const route = this.owner.lookup('route:notes');
assert.ok(route);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'frontend-src/tests/helpers';
module('Unit | Route | notes/index', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
const route = this.owner.lookup('route:notes/index');
assert.ok(route);
});
});

View file

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'frontend-src/tests/helpers';
module('Unit | Route | notes/note', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
const route = this.owner.lookup('route:notes/note');
assert.ok(route);
});
});

View file

@ -0,0 +1,14 @@
{
"extends": "@tsconfig/ember/tsconfig.json",
"compilerOptions": {
// The combination of `baseUrl` with `paths` allows Ember's classic package
// layout, which is not resolvable with the Node resolution algorithm, to
// work with TypeScript.
"baseUrl": ".",
"paths": {
"frontend-src/tests/*": ["tests/*"],
"frontend-src/*": ["app/*"],
"*": ["types/*"]
}
}
}

View file

@ -0,0 +1,7 @@
/**
* Catch-all for ember-data.
*/
export default interface ModelRegistry {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}

1
frontend-src/types/global.d.ts vendored Normal file
View file

@ -0,0 +1 @@
import '@glint/environment-ember-loose';

8
future-useful-libs.md Normal file
View file

@ -0,0 +1,8 @@
- golang.org/x/net/html
- Parsing and manipulating html
- https://github.com/chasefleming/elem-go
- Generating html
- mime
- working with mime types
- https://github.com/tursodatabase/go-libsql
- sqlite but probably better (and should also be able to compile to a static binary)

20
go.mod
View file

@ -6,13 +6,18 @@ toolchain go1.23.0
require ( require (
github.com/BurntSushi/toml v1.4.0 github.com/BurntSushi/toml v1.4.0
github.com/bradfitz/gomemcache v0.0.0-20230124162541-5f7a7d875746 github.com/dgraph-io/ristretto v0.1.1
github.com/eko/gocache/lib/v4 v4.1.6 github.com/eko/gocache/lib/v4 v4.1.6
github.com/eko/gocache/store/memcache/v4 v4.2.2 github.com/eko/gocache/store/redis/v4 v4.2.2
github.com/eko/gocache/store/ristretto/v4 v4.2.2
github.com/glebarez/sqlite v1.11.0 github.com/glebarez/sqlite v1.11.0
github.com/go-webauthn/webauthn v0.11.2 github.com/go-webauthn/webauthn v0.11.2
github.com/google/uuid v1.6.0
github.com/mstarongithub/passkey v0.0.0-20240817142622-de6912c8303e github.com/mstarongithub/passkey v0.0.0-20240817142622-de6912c8303e
github.com/redis/go-redis/v9 v9.0.2
github.com/rs/zerolog v1.33.0 github.com/rs/zerolog v1.33.0
github.com/xhit/go-simple-mail/v2 v2.16.0
gitlab.com/mstarongitlab/goap v1.1.0
gitlab.com/mstarongitlab/goutils v1.3.0 gitlab.com/mstarongitlab/goutils v1.3.0
gorm.io/driver/postgres v1.5.7 gorm.io/driver/postgres v1.5.7
gorm.io/gorm v1.25.10 gorm.io/gorm v1.25.10
@ -21,22 +26,17 @@ require (
require ( require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/eko/gocache/store/redis/v4 v4.2.2 // indirect
github.com/eko/gocache/store/ristretto/v4 v4.2.2 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/piprate/json-gold v0.5.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/redis/go-redis/v9 v9.0.2 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
@ -48,26 +48,26 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-test/deep v1.1.1 // indirect
github.com/go-webauthn/x v0.1.14 // indirect github.com/go-webauthn/x v0.1.14 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/google/go-tpm v0.9.1 // indirect github.com/google/go-tpm v0.9.1 // indirect
github.com/google/uuid v1.6.0
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.4.3 // indirect github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/piprate/json-gold v0.5.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/stretchr/testify v1.9.0 // indirect
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
gitlab.com/mstarongitlab/goap v1.1.0
golang.org/x/crypto v0.26.0 // indirect golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.23.0 // indirect golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect golang.org/x/text v0.17.0 // indirect

20
go.sum
View file

@ -44,11 +44,12 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/gomemcache v0.0.0-20230124162541-5f7a7d875746 h1:wAIE/kN63Oig1DdOzN7O+k4AbFh2cCJoKMFXrwRJtzk= github.com/bsm/ginkgo/v2 v2.5.0 h1:aOAnND1T40wEdAtkGSkvSICWeQ8L3UASX7YVCqQx+eQ=
github.com/bradfitz/gomemcache v0.0.0-20230124162541-5f7a7d875746/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/gomega v1.20.0 h1:JhAwLmtRzXFTx2AkALSLa8ijZafntmhSoU63Ok18Uq8=
github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -58,7 +59,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38 h1:cUoduvNB9/JFJYEVeKy2hX/R5qyg2uwnHVhXCIjhBeI= github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38 h1:cUoduvNB9/JFJYEVeKy2hX/R5qyg2uwnHVhXCIjhBeI=
github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38/go.mod h1:a0PnbhSGmzFMGx9KdEqfEdDHoEwTF9KLNbKLcWD8kAo= github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38/go.mod h1:a0PnbhSGmzFMGx9KdEqfEdDHoEwTF9KLNbKLcWD8kAo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -66,6 +66,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
@ -74,8 +75,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/eko/gocache/lib/v4 v4.1.6 h1:5WWIGISKhE7mfkyF+SJyWwqa4Dp2mkdX8QsZpnENqJI= github.com/eko/gocache/lib/v4 v4.1.6 h1:5WWIGISKhE7mfkyF+SJyWwqa4Dp2mkdX8QsZpnENqJI=
github.com/eko/gocache/lib/v4 v4.1.6/go.mod h1:HFxC8IiG2WeRotg09xEnPD72sCheJiTSr4Li5Ameg7g= github.com/eko/gocache/lib/v4 v4.1.6/go.mod h1:HFxC8IiG2WeRotg09xEnPD72sCheJiTSr4Li5Ameg7g=
github.com/eko/gocache/store/memcache/v4 v4.2.2 h1:VKfxytQ5bkcfF3LhmgkrqRiEU2yCN2/rJBUvF1fKZJw=
github.com/eko/gocache/store/memcache/v4 v4.2.2/go.mod h1:9lFU3tZPiej8E3J4ueZ0K9kIdiDQpRxu6WhtId5OsZA=
github.com/eko/gocache/store/redis/v4 v4.2.2 h1:Thw31fzGuH3WzJywsdbMivOmP550D6JS7GDHhvCJPA0= github.com/eko/gocache/store/redis/v4 v4.2.2 h1:Thw31fzGuH3WzJywsdbMivOmP550D6JS7GDHhvCJPA0=
github.com/eko/gocache/store/redis/v4 v4.2.2/go.mod h1:LaTxLKx9TG/YUEybQvPMij++D7PBTIJ4+pzvk0ykz0w= github.com/eko/gocache/store/redis/v4 v4.2.2/go.mod h1:LaTxLKx9TG/YUEybQvPMij++D7PBTIJ4+pzvk0ykz0w=
github.com/eko/gocache/store/ristretto/v4 v4.2.2 h1:lXFzoZ5ck6Gy6ON7f5DHSkNt122qN7KoroCVgVwF7oo= github.com/eko/gocache/store/ristretto/v4 v4.2.2 h1:lXFzoZ5ck6Gy6ON7f5DHSkNt122qN7KoroCVgVwF7oo=
@ -102,6 +101,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-webauthn/webauthn v0.11.2 h1:Fgx0/wlmkClTKlnOsdOQ+K5HcHDsDcYIvtYmfhEOSUc= github.com/go-webauthn/webauthn v0.11.2 h1:Fgx0/wlmkClTKlnOsdOQ+K5HcHDsDcYIvtYmfhEOSUc=
github.com/go-webauthn/webauthn v0.11.2/go.mod h1:aOtudaF94pM71g3jRwTYYwQTG1KyTILTcZqN1srkmD0= github.com/go-webauthn/webauthn v0.11.2/go.mod h1:aOtudaF94pM71g3jRwTYYwQTG1KyTILTcZqN1srkmD0=
github.com/go-webauthn/x v0.1.14 h1:1wrB8jzXAofojJPAaRxnZhRgagvLGnLjhCAwg3kTpT0= github.com/go-webauthn/x v0.1.14 h1:1wrB8jzXAofojJPAaRxnZhRgagvLGnLjhCAwg3kTpT0=
@ -203,9 +204,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -284,8 +284,12 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA=
github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

5
mailer/NewUserRequest.go Normal file
View file

@ -0,0 +1,5 @@
package mailer
type NewUserMailData struct {
Domain string
}

12
mailer/mail.go Normal file
View file

@ -0,0 +1,12 @@
package mailer
import (
"io/fs"
mail "github.com/xhit/go-simple-mail/v2"
)
type MailClient struct {
mailServer *mail.SMTPServer
templatesFs fs.FS
}

View file

@ -0,0 +1,23 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>New user request</title>
<link href="{{ .Domain }}/static/css/NewUserRequest.css" rel="stylesheet" />
</head>
<body>
<h1>New account request</h1>
<p>New user is awaiting account approval</p>
<h3>Information</h3>
<ul>
<li>Account name: {{ .Username }}</li>
<li>Account mail: {{ .MailAddress }}</li>
</ul>
<h4>Request reason</h4>
<p>{{ .Reason }}</p>
</body>
</html>

View file

@ -1,3 +1,4 @@
// TODO: Add EUPL banner everywhere
package main package main
import ( import (
@ -48,6 +49,10 @@ func main() {
log.Fatal().Err(err).Msg("Failed to setup storage") log.Fatal().Err(err).Msg("Failed to setup storage")
} }
_ = store _ = store
// TODO: Set up media server
// TODO: Set up http server
// TODO: Set up plugins
// TODO: Start everything
} }
func setLogLevel() { func setLogLevel() {

View file

@ -0,0 +1,21 @@
package outgoingeventqueue
// TODO: Implement me
/*
Queue for controlled distribution of outgoing events, such as note creations, deletions or updates
Also has to manage the case where an instance can't be reached or where Linstrom has to shut down
In case of a shutdown, it has to store all remaining tasks in the db to try again later after the next boot
Should preferably also be able to tell when a server is just gone and stop bothering about it
Implementation idea: New job gets send to queue (via function call). Queue then launches a new goroutine for that job
Goroutine then launches multiple new goroutines, one per targeted inbox, filtered by blocked targets
Each of those will wait for a ticker or a stop signal
On each ticker they'll try to deliver the payload to the target inbox
If a stop signal comes in, push the payload and goal into the db to pick up again later
On stop or sucessful delivery, exit the goroutine
Stop can also be used to suspend outbound traffic to another instance to help reduce the load on them
TODO: Think of ways to make this more configurable for how data is being sent how fast
*/

View file

@ -1,17 +0,0 @@
package middlewares
import (
"net/http"
"github.com/rs/zerolog/log"
)
const CONTEXT_KEY_LOGRUS = ContextKey("logrus")
// Inject a logrus entry into the context that has the url path already set
func InjectLogrusMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
newContext := log.With().Str("url-path", r.URL.RawPath).Logger().WithContext(r.Context())
next.ServeHTTP(w, r.WithContext(newContext))
})
}

View file

@ -1,22 +0,0 @@
package middlewares
import (
"context"
"net/http"
"gitlab.com/mstarongitlab/linstrom/storage"
)
const CONTEXT_KEY_STORAGE = ContextKey("storage")
// Build a middleware for injecting a storage reference into the context
func InjectStorageMiddlewareBuilder(store *storage.Storage) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reqContext := r.Context()
newContext := context.WithValue(reqContext, CONTEXT_KEY_STORAGE, store)
newRequest := r.WithContext(newContext)
h.ServeHTTP(w, newRequest)
})
}
}

View file

@ -1,14 +0,0 @@
package middlewares
import "net/http"
type ContextKey string
type MiddlewareFunc func(http.Handler) http.Handler
func ChainMiddlewares(start http.Handler, middlewares ...MiddlewareFunc) http.Handler {
next := start
for _, h := range middlewares {
next = h(next)
}
return next
}

View file

@ -1,23 +0,0 @@
package server
import (
"net/http"
"gitlab.com/mstarongitlab/linstrom/ap"
)
// Mount at /notes/{note-id}
// Handles the note endpoint
// Serves the json-ld representation of a note OR the frontend view
func noteHandler(w http.ResponseWriter, r *http.Request) {
if ap.ContainsApContentHeader(r.Header.Get("Content-Type")) {
apNote(w, r)
} else {
renderNote(w, r)
}
}
func renderNote(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not implemented yet", http.StatusInternalServerError)
}
func apNote(w http.ResponseWriter, r *http.Request) {}

View file

@ -1,27 +0,0 @@
package server
import (
"net/http"
"gitlab.com/mstarongitlab/linstrom/server/middlewares"
"gitlab.com/mstarongitlab/linstrom/storage"
)
type Server struct {
handler http.Handler
}
func NewServer(store *storage.Storage) *Server {
handler := http.NewServeMux()
handler.HandleFunc("/.well-known/webfinger", webfingerHandler)
// handler.Handle("/api/", http.StripPrefix("/ap", buildApiRouter()))
withMiddlewares := middlewares.ChainMiddlewares(
handler,
middlewares.InjectLogrusMiddleware,
middlewares.InjectStorageMiddlewareBuilder(store),
)
return &Server{
handler: withMiddlewares,
}
}

View file

@ -42,7 +42,9 @@ func (p *EncoderPool) Encode(raw any) ([]byte, error) {
defer encoder.Unlock() defer encoder.Unlock()
// Clear the buffer to avoid funky output from previous operations // Clear the buffer to avoid funky output from previous operations
encoder.Buffer.Reset() encoder.Buffer.Reset()
encoder.Encoder.Encode(raw) if err := encoder.Encoder.Encode(raw); err != nil {
return nil, err
}
data, err := io.ReadAll(encoder.Buffer) data, err := io.ReadAll(encoder.Buffer)
if err != nil { if err != nil {
return nil, err return nil, err

6
storage/housekeeping.go Normal file
View file

@ -0,0 +1,6 @@
package storage
// Contains various functions for housekeeping
// Things like true deletion of soft deleted data after some time
// Or removing inactive access tokens
// All of this will be handled by goroutines

View file

@ -26,14 +26,52 @@ type MediaMetadata struct {
Name string Name string
} }
// TODO: Figure out how to actually manage media. Because this current idea sucks func (s *Storage) NewMediaMetadata(location, mediaType, name string) (*MediaMetadata, error) {
// One idea would be to make another storage provider, but purely focused on handling the files
// and then using this section to store metadata about the files it knows
func (s *Storage) NewMediaMetadata(url, mediaType, name string) (*MediaMetadata, error) {
newMedia := MediaMetadata{ newMedia := MediaMetadata{
Location: url, Location: location,
Name: name, Name: name,
Type: mediaType,
} }
s.db.Create(&newMedia) s.db.Create(&newMedia)
return nil, nil return nil, nil
} }
func (s *Storage) FuzzyFindMediaMetadataByName(name string) ([]MediaMetadata, error) {
notes := []MediaMetadata{}
err := s.db.Where("name LIKE %?%", name).Find(notes).Error
if err != nil {
return nil, err
}
return notes, nil
}
func (s *Storage) GetMediaMetadataById(id string) (*MediaMetadata, error) {
media := MediaMetadata{ID: id}
err := s.db.First(&media).Error
if err != nil {
return nil, err
}
return &media, nil
}
func (s *Storage) FuzzyFindMediaMetadataByLocation(location string) ([]MediaMetadata, error) {
data := []MediaMetadata{}
if err := s.db.Where("location LIKE %?%", location).Find(data).Error; err != nil {
return nil, err
}
return data, nil
}
func (s *Storage) DeleteMediaMetadataById(id string) error {
return s.db.Delete(MediaMetadata{ID: id}).Error
}
func (s *Storage) DeleteMediaMetadataByFuzzyLocation(location string) error {
var tmp MediaMetadata
return s.db.Where("location LIKE %?%", location).Delete(&tmp).Error
}
func (s *Storage) DeleteMediaMetadataByFuzzyName(name string) error {
var tmp MediaMetadata
return s.db.Where("name LIKE %?%", name).Delete(&tmp).Error
}

View file

@ -0,0 +1,3 @@
package mediaprovider
// TODO: Implement me

View file

@ -121,3 +121,13 @@ func (s *Storage) DeleteNote(id string) {
s.cache.Delete(cacheNoteIdToNotePrefix + id) s.cache.Delete(cacheNoteIdToNotePrefix + id)
s.db.Delete(Note{ID: id}) s.db.Delete(Note{ID: id})
} }
// Try and find a note with a given ID
func (store *Storage) FindNoteById(id string) (*Note, error) {
note := Note{}
res := store.db.First(&note, id)
if res.Error != nil {
return nil, res.Error
}
return &note, nil
}

View file

@ -1,5 +1,7 @@
package storage package storage
// TODO: More helper stuff
func (s *Storage) NewRemoteUser(fullHandle string) (*Account, error) { func (s *Storage) NewRemoteUser(fullHandle string) (*Account, error) {
return nil, nil return nil, nil
} }

View file

@ -5,4 +5,7 @@ type Role struct {
Name string Name string
// If set, counts as all permissions being set and all restrictions being disabled // If set, counts as all permissions being set and all restrictions being disabled
FullAdmin bool FullAdmin bool
// TODO: More control options
// Extend upon whatever Masto, Akkoma and Misskey have
// Lots of details please
} }

View file

@ -1,7 +1,13 @@
// TODO: Unify function names
// Storage is the handler for cache and db access
// It handles storing various data in the database as well as caching that data
// Said data includes notes, accounts, metadata about media files, servers and similar
package storage package storage
import ( import (
"errors" "errors"
"fmt"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gitlab.com/mstarongitlab/linstrom/storage/cache" "gitlab.com/mstarongitlab/linstrom/storage/cache"
@ -41,3 +47,8 @@ func NewStorage(dbUrl string, cache *cache.Cache) (*Storage, error) {
return &Storage{db, cache}, nil return &Storage{db, cache}, nil
} }
// TODO: Placeholder. Update to proper implementation later. Including signature
func (s *Storage) FindLocalAccount(handle string) (string, error) {
return handle, nil
}

View file

@ -13,3 +13,5 @@ type UserInfoField struct {
Value string Value string
LastUrlCheckDate *time.Time // Used if the value is an url to somewhere. Empty if value is not an url LastUrlCheckDate *time.Time // Used if the value is an url to somewhere. Empty if value is not an url
} }
// TODO: Add functions to store, load, update and delete these

View file

@ -0,0 +1,34 @@
package storage
type AccountRestriction int64
const (
// Account has no restrictions applied
ACCOUNT_RESTRICTION_NONE = AccountRestriction(0)
// All messages of the account get a content warning applied if none is set
// Warning could be something like "Message auto-CWd by server"
ACCOUNT_RESTRICTION_AUTO_CW = AccountRestriction(1 << iota)
// Disable accessing the account via login or access token
ACCOUNT_RESTRICTION_DISABLE_LOGIN
// Disable sending activities to other servers if the account is local
// Or reject all activities if the account is remote
ACCOUNT_RESTRICTION_NO_FEDERATION
// Disallow sending direct messages from that account
ACCOUNT_RESTRICTION_NO_DMS
// Disallow sending follower only messages from that account
ACCOUNT_RESTRICTION_NO_FOLLOWER_POSTS
// Disable outbound follow requests (restricted account can't send follow requests)
ACCOUNT_RESTRICTION_DISABLE_OUTBOUND_FOLLOWS
// Disable inbound follow requests (all follow requests to that account are automatically rejected)
ACCOUNT_RESTRICTION_DISABLE_INBOUND_FOLLOWS
// Forces all posts by that account to be follower only
ACCOUNT_RESTRICTION_FORCE_FOLLOWERS_ONLY
// Disable all outbound activities of an account.
// Includes sending, updating or deleting own notes
// as well as boosting or reacting to any notes
ACCOUNT_RESTRICTION_DISABLE_ACTIVITIES
// Account can only be viewed while logged in or via verified requests to the AP endpoints
ACCOUNT_RESTRICTIONS_NO_PUBLIC_ACCESS
// Force tag all media the account posts as sensitive
ACCOUNT_RESTRICTIONS_FORCE_MEDIA_SENSITIVE
)