Compare commits
2 Commits
b975a6e96a
...
0f990db1ea
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f990db1ea | |||
| efe53ad5a1 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -46,7 +46,7 @@ test.log
|
||||
/.stack-work.lock
|
||||
/.npmrc
|
||||
/.npm/
|
||||
/config/webpack.yml
|
||||
/config/manifest.json
|
||||
tunnel.log
|
||||
/static
|
||||
/well-known
|
||||
|
||||
2
Makefile
2
Makefile
@ -206,9 +206,9 @@ serve-backend:
|
||||
|
||||
# TODO: better name
|
||||
.PHONY: db
|
||||
# HELP: clear and fill database. requires running postgres
|
||||
db: FRADRIVE_SERVICE=backend
|
||||
db: --image-build --containerized---db;
|
||||
# HELP(db-cf-backend): clear and fill database. requires running postgres
|
||||
# TODO (db-m-$MIGRATION-backend): apply migration (see src/Model/Migration/Definition.hs for list of available migrations)
|
||||
--db-backend: .stack
|
||||
SERVER_SESSION_ACID_FALLBACK=${SERVER_SESSION_ACID_FALLBACK:-true} ; \
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -9,9 +9,9 @@
|
||||
|
||||
static-dir: "_env:STATIC_DIR:static"
|
||||
well-known-dir: "_env:WELL_KNOWN_DIR:well-known"
|
||||
well-known-link-file: html_code.html
|
||||
well-known-link-file: include.html
|
||||
|
||||
webpack-manifest: "_env:WEBPACK_MANIFEST:config/webpack.yml"
|
||||
bundler-manifest: "_env:BUNDLER_MANIFEST:config/manifest.json"
|
||||
host: "_env:HOST:*4" # any IPv4 host
|
||||
port: "_env:PORT:3000"
|
||||
ip-from-header: "_env:IP_FROM_HEADER:false"
|
||||
|
||||
@ -1,36 +1,65 @@
|
||||
import * as esbuild from 'esbuild';
|
||||
|
||||
import { sassPlugin } from 'esbuild-sass-plugin';
|
||||
import svgPlugin from 'esbuild-plugin-svg-bundle';
|
||||
// import svgPlugin from 'esbuild-plugin-svg-bundle';
|
||||
import svgPlugin from 'esbuild-plugin-svg';
|
||||
import { copy } from 'esbuild-plugin-copy';
|
||||
// import manifestPlugin from 'esbuild-plugin-manifest';
|
||||
import manifestPlugin from 'esbuild-plugin-assets-manifest';
|
||||
import copyWithHashPlugin from '@enonic/esbuild-plugin-copy-with-hash';
|
||||
import inlineImportPlugin from 'esbuild-plugin-inline-import';
|
||||
|
||||
const staticDir = './static';
|
||||
const wellKnownDir = './well-known';
|
||||
|
||||
await esbuild.build({
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
entryPoints: {
|
||||
main: './frontend/src/main.js',
|
||||
polyfill: './frontend/src/polyfill.js',
|
||||
},
|
||||
outdir: staticDir,
|
||||
plugins: [
|
||||
sassPlugin(),
|
||||
svgPlugin({
|
||||
bundleFile: './svg-bundle.svg',
|
||||
bundleUrl: './svg-bundle.svg',
|
||||
minify: true,
|
||||
// bundleFile: `${wellKnownDir}/svg-bundle.svg`,
|
||||
// bundleUrl: `${wellKnownDir}/svg-bundle.svg`,
|
||||
}),
|
||||
copy({
|
||||
resolveFrom: 'cwd',
|
||||
assets: {
|
||||
from: [ './assets/favicons/*' ],
|
||||
to: [ './static' ],
|
||||
to: [ `${wellKnownDir}/de-de-formal`, `${wellKnownDir}/en-eu` ],
|
||||
},
|
||||
}),
|
||||
copy({
|
||||
resolveFrom: 'cwd',
|
||||
assets: {
|
||||
from: [ './config/robots.txt' ],
|
||||
to: [ './static' ],
|
||||
to: [ `${wellKnownDir}/de-de-formal`, `${wellKnownDir}/en-eu` ],
|
||||
},
|
||||
}),
|
||||
// ...['de-de-formal','en-eu'].map((lang) => manifestPlugin({
|
||||
manifestPlugin({
|
||||
filename: 'manifest.json',
|
||||
path: 'config',
|
||||
// metadata: { timestamp: new Date(), module: 'myapp', type: 'esm', },
|
||||
processOutput(assets) {
|
||||
const orderAssets = {
|
||||
main: assets['main'],
|
||||
...assets
|
||||
};
|
||||
return JSON.stringify(orderAssets, null, ' ');
|
||||
},
|
||||
}),
|
||||
/* copyWithHashPlugin({
|
||||
patterns: [
|
||||
'./assets/favicons/*',
|
||||
'./config/robots.txt',
|
||||
],
|
||||
}), */
|
||||
],
|
||||
entryPoints: [
|
||||
'./frontend/src/main.js',
|
||||
'./frontend/src/polyfill.js',
|
||||
],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
outdir: './static',
|
||||
});
|
||||
343
package-lock.json
generated
343
package-lock.json
generated
@ -35,6 +35,7 @@
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.7",
|
||||
"@babel/plugin-transform-runtime": "^7.25.4",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"@enonic/esbuild-plugin-copy-with-hash": "^0.2.0",
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
@ -45,7 +46,11 @@
|
||||
"css-loader": "^7.1.2",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"esbuild": "0.24.0",
|
||||
"esbuild-plugin-assets-manifest": "^1.0.8",
|
||||
"esbuild-plugin-copy": "2.1.1",
|
||||
"esbuild-plugin-inline-import": "^1.1.0",
|
||||
"esbuild-plugin-manifest": "1.0.4",
|
||||
"esbuild-plugin-svg": "^0.1.0",
|
||||
"esbuild-plugin-svg-bundle": "1.3.0",
|
||||
"esbuild-sass-plugin": "3.3.1",
|
||||
"eslint": "^9.9.1",
|
||||
@ -2009,6 +2014,72 @@
|
||||
"license": "(Apache-2.0 AND BSD-3-Clause)",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cjs-exporter/globby": {
|
||||
"version": "13.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@cjs-exporter/globby/-/globby-13.1.3.tgz",
|
||||
"integrity": "sha512-rxSVbUhNmIYTZKzrtb6cJIUfFk0PDxzeR4+dzi8edKYmmbqRBO/k7N+tW///QmtY6OznemXiLMSZ20E6DHegxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"globby": "13.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@cjs-exporter/globby/node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cjs-exporter/globby/node_modules/globby": {
|
||||
"version": "13.1.3",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
|
||||
"integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dir-glob": "^3.0.1",
|
||||
"fast-glob": "^3.2.11",
|
||||
"ignore": "^5.2.0",
|
||||
"merge2": "^1.4.1",
|
||||
"slash": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@cjs-exporter/globby/node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cjs-exporter/globby/node_modules/slash": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
|
||||
"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||
@ -3077,6 +3148,21 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@enonic/esbuild-plugin-copy-with-hash": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@enonic/esbuild-plugin-copy-with-hash/-/esbuild-plugin-copy-with-hash-0.2.0.tgz",
|
||||
"integrity": "sha512-2KX60dKlPx5Q7d3Jz+23hekbHrCTZzvlZC4U+rLZiP3GMbumEq5lmocw5XKLNTvHtRwNlUze+3TwiXSCD46EeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cjs-exporter/globby": "^13.1.3",
|
||||
"colorette": "^2.0.20",
|
||||
"xxh3-ts": "^1.0.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"esbuild": "~0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
|
||||
@ -4816,8 +4902,7 @@
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
@ -6287,6 +6372,23 @@
|
||||
"postcss": "^8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
|
||||
"integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.0.1",
|
||||
"domhandler": "^4.3.1",
|
||||
"domutils": "^2.8.0",
|
||||
"nth-check": "^2.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
|
||||
@ -6840,6 +6942,21 @@
|
||||
"void-elements": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domain-browser": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||
@ -6865,6 +6982,37 @@
|
||||
],
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer2": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||
@ -7072,6 +7220,16 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/env-paths": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||
@ -7282,6 +7440,16 @@
|
||||
"@esbuild/win32-x64": "0.24.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-assets-manifest": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-assets-manifest/-/esbuild-plugin-assets-manifest-1.0.8.tgz",
|
||||
"integrity": "sha512-2goWUmBLpqaHASkMQIgsSqcAs3Y1rDMKcOjk8cWOTtAzmbHYQLh77MEjuQYDx3bBEQ9dVZCaU0/cBIjhvdJf+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"esbuild": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-copy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-copy/-/esbuild-plugin-copy-2.1.1.tgz",
|
||||
@ -7453,6 +7621,36 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-inline-import": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-inline-import/-/esbuild-plugin-inline-import-1.1.0.tgz",
|
||||
"integrity": "sha512-b0xX4tPKBdRjX1CkzpnULpEdeTo9vxD+wf83PKvgUYnOEaJfVxLey4q+sfTUPAdDnRRYasJsQUgQW7/e2Gm5Dw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esbuild-plugin-manifest": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-manifest/-/esbuild-plugin-manifest-1.0.4.tgz",
|
||||
"integrity": "sha512-z+aDPuNIFZto5cYZhZwYk+aWhSqi8yShxx6Yfz+gqMKu+mIrYRtJztxoI2GNIv9hcsEatn+uInkEbf20kTZLxA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"proper-lockfile": "^4.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"esbuild": "~0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-svg/-/esbuild-plugin-svg-0.1.0.tgz",
|
||||
"integrity": "sha512-/9ZhvIpl+Ovl6glVK3BedvIwrOwSQnECw4Fy6ZwysWib3Ns7UkX6WNGjMOWtvQ1Cnm0uc7sptiKGm0BthKCAJA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"svgo": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg-bundle": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-plugin-svg-bundle/-/esbuild-plugin-svg-bundle-1.3.0.tgz",
|
||||
@ -7514,6 +7712,72 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg/node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg/node_modules/css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg/node_modules/csso": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
|
||||
"integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"css-tree": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg/node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/esbuild-plugin-svg/node_modules/svgo": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
|
||||
"integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@trysound/sax": "0.2.0",
|
||||
"commander": "^7.2.0",
|
||||
"css-select": "^4.1.3",
|
||||
"css-tree": "^1.1.3",
|
||||
"csso": "^4.2.0",
|
||||
"picocolors": "^1.0.0",
|
||||
"stable": "^0.1.8"
|
||||
},
|
||||
"bin": {
|
||||
"svgo": "bin/svgo"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sass-plugin": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz",
|
||||
@ -8934,8 +9198,7 @@
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
@ -15391,6 +15654,25 @@
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/proper-lockfile": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
|
||||
"integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"retry": "^0.12.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/proper-lockfile/node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@ -15907,6 +16189,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
@ -17015,6 +17307,14 @@
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/stable": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
|
||||
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
|
||||
"deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
@ -19055,6 +19355,41 @@
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/xxh3-ts": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/xxh3-ts/-/xxh3-ts-1.0.6.tgz",
|
||||
"integrity": "sha512-mFdXT/i6svQNNmwICmszSfKgnYBGBIaCKzPxYHfpM6e1hxYX2gfGPrI9mKRzSnFpi6ieBIK88TGlaudcPYZW5g==",
|
||||
"dev": true,
|
||||
"license": "BSD-2 Clause",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/xxh3-ts/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.7",
|
||||
"@babel/plugin-transform-runtime": "^7.25.4",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"@enonic/esbuild-plugin-copy-with-hash": "^0.2.0",
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
@ -31,7 +32,11 @@
|
||||
"css-loader": "^7.1.2",
|
||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||
"esbuild": "0.24.0",
|
||||
"esbuild-plugin-assets-manifest": "^1.0.8",
|
||||
"esbuild-plugin-copy": "2.1.1",
|
||||
"esbuild-plugin-inline-import": "^1.1.0",
|
||||
"esbuild-plugin-manifest": "1.0.4",
|
||||
"esbuild-plugin-svg": "^0.1.0",
|
||||
"esbuild-plugin-svg-bundle": "1.3.0",
|
||||
"esbuild-sass-plugin": "3.3.1",
|
||||
"eslint": "^9.9.1",
|
||||
@ -80,6 +85,7 @@
|
||||
"whatwg-fetch": "^3.6.20"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node esbuild.config.mjs"
|
||||
"build": "node esbuild.config.mjs",
|
||||
"start": "node esbuild.config.mjs --watch"
|
||||
}
|
||||
}
|
||||
|
||||
5
routes
5
routes
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>, Sarah Vaupel <sarah.vaupel@ifi.lmu.de>, Steffen Jost <jost@tcs.ifi.lmu.de>, Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
-- !development -- like free, but only for development builds
|
||||
|
||||
/static StaticR EmbeddedStatic appStatic !free
|
||||
|
||||
/auth AuthR Auth getAuth !free
|
||||
|
||||
/metrics MetricsR GET !free -- verify if this can be free
|
||||
@ -297,4 +298,4 @@
|
||||
/swagger SwaggerR GET !free
|
||||
/swagger.json SwaggerJsonR GET !free
|
||||
|
||||
!/*WellKnownFileName WellKnownR GET !free
|
||||
!/*WellKnownFileName WellKnownR GET !free
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -91,7 +91,9 @@ instance Yesod UniWorX where
|
||||
isAuthorized :: HasCallStack => Route UniWorX -> Bool -> HandlerFor UniWorX AuthResult
|
||||
isAuthorized r w = runDBRead $ evalAccess r w
|
||||
|
||||
-- TODO: replace memcached-based static-content caching with basic addStaticContent
|
||||
addStaticContent = UniWorX.addStaticContent
|
||||
-- addStaticContent = embedStaticContent appStatic StaticR Right -- TODO: minify on production builds
|
||||
|
||||
fileUpload _site _length = FileUploadMemory lbsBackEnd
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Winnie Ros <winnie.ros@campus.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -488,7 +488,8 @@ siteLayout' overrideHeading widget = do
|
||||
frontendDatetimeLocale <- toJSON <$> selectLanguage frontendDatetimeLocales
|
||||
|
||||
pc <- widgetToPageContent $ do
|
||||
webpackLinks_main StaticR
|
||||
bundlerLinks_main StaticR
|
||||
bundlerLinks_polyfill StaticR
|
||||
toWidget $(juliusFile "templates/i18n.julius")
|
||||
whenIsJust currentApproot' $ \currentApproot ->
|
||||
toWidget $(juliusFile "templates/approot.julius")
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -90,7 +90,7 @@ import qualified Data.Set as Set
|
||||
data AppSettings = AppSettings
|
||||
{ appStaticDir :: FilePath
|
||||
-- ^ Directory from which to serve static files.
|
||||
, appWebpackEntrypoints :: FilePath
|
||||
, appBundlerEntrypoints :: FilePath
|
||||
, appWellKnownDir :: FilePath
|
||||
, appWellKnownLinkFile :: FilePath
|
||||
, appDatabaseConf :: PostgresConf
|
||||
@ -624,7 +624,7 @@ instance FromJSON AppSettings where
|
||||
appStaticDir <- o .: "static-dir"
|
||||
appWellKnownDir <- o .: "well-known-dir"
|
||||
appWellKnownLinkFile <- o .: "well-known-link-file"
|
||||
appWebpackEntrypoints <- o .: "webpack-manifest"
|
||||
appBundlerEntrypoints <- o .: "bundler-manifest"
|
||||
appDatabaseConf <- o .: "database"
|
||||
appAutoDbMigrate <- o .: "auto-db-migrate"
|
||||
let nonEmptyHost LdapConf{..} = case ldapHost of
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Steffen Jost <jost@cip.ifi.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>, Steffen Jost <jost@cip.ifi.lmu.de>, Steffen Jost <jost@tcs.ifi.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -7,16 +7,16 @@
|
||||
-- prevents rebuilds if files change, that are not directly used (like
|
||||
-- webpack bundles)
|
||||
module Settings.StaticFiles
|
||||
( webpackLinks_main
|
||||
( bundlerLinks_main, bundlerLinks_polyfill
|
||||
, embeddedStatic
|
||||
, module Yesod.EmbeddedStatic
|
||||
) where
|
||||
|
||||
import ClassyPrelude.Yesod
|
||||
|
||||
import Settings (appStaticDir, appWebpackEntrypoints, compileTimeAppSettings)
|
||||
import Settings (appStaticDir, appBundlerEntrypoints, compileTimeAppSettings)
|
||||
import Settings.StaticFiles.Generator
|
||||
import Settings.StaticFiles.Webpack
|
||||
import Settings.StaticFiles.Bundler
|
||||
import Yesod.EmbeddedStatic
|
||||
|
||||
-- This generates easy references to files in the static directory at compile time,
|
||||
@ -35,4 +35,4 @@ import Yesod.EmbeddedStatic
|
||||
#endif
|
||||
|
||||
mkEmbeddedStatic DEV_BOOL "embeddedStatic" . pure . staticGenerator $ appStaticDir compileTimeAppSettings
|
||||
mkWebpackEntrypoints (appWebpackEntrypoints compileTimeAppSettings) (pure staticGenerator) $ appStaticDir compileTimeAppSettings
|
||||
mkBundlerEntrypoints (appBundlerEntrypoints compileTimeAppSettings) (pure staticGenerator) $ appStaticDir compileTimeAppSettings
|
||||
@ -1,9 +1,9 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
module Settings.StaticFiles.Webpack
|
||||
( mkWebpackEntrypoints
|
||||
module Settings.StaticFiles.Bundler
|
||||
( mkBundlerEntrypoints
|
||||
) where
|
||||
|
||||
import ClassyPrelude
|
||||
@ -12,7 +12,7 @@ import Language.Haskell.TH
|
||||
import Language.Haskell.TH.Syntax hiding (Lift(..))
|
||||
import qualified Language.Haskell.TH.Syntax as TH (Lift(..))
|
||||
|
||||
import qualified Data.Yaml as Yaml
|
||||
import qualified Data.Aeson as Aeson
|
||||
|
||||
import qualified Data.Map as Map
|
||||
|
||||
@ -25,7 +25,6 @@ import Control.Lens.Indexed (iforM)
|
||||
|
||||
import Control.Monad.Writer.Class (MonadWriter(..))
|
||||
import Control.Monad.Trans.Writer.Lazy (execWriterT)
|
||||
import Control.Monad.Catch (MonadThrow(..))
|
||||
|
||||
import System.FilePath (makeRelative)
|
||||
|
||||
@ -35,11 +34,11 @@ import Utils ()
|
||||
import Data.Containers.ListUtils
|
||||
|
||||
|
||||
mkWebpackEntrypoints :: FilePath -- ^ Path to YAML-manifest
|
||||
mkBundlerEntrypoints :: FilePath -- ^ Path to manifest (json)
|
||||
-> [FilePath -> Generator]
|
||||
-> FilePath -- ^ Path to static dir
|
||||
-> DecsQ
|
||||
mkWebpackEntrypoints manifest mkGen stDir = do
|
||||
mkBundlerEntrypoints manifest mkGen stDir = do
|
||||
addDependentFile manifest
|
||||
entrypoints <- decodeManifest manifest
|
||||
|
||||
@ -54,14 +53,14 @@ mkWebpackEntrypoints manifest mkGen stDir = do
|
||||
, ebLocation entry
|
||||
, "” of file “"
|
||||
, file
|
||||
, "” of webpack entrypoint “"
|
||||
, "” of bundler entrypoint “"
|
||||
, entrypoint
|
||||
, "” has no haskellName"
|
||||
]
|
||||
Just n -> tell $ pure (n, ebMimeType entry)
|
||||
|
||||
let entryName = mkName $ "webpackEntrypoint_" <> entrypoint
|
||||
widgetName = mkName $ "webpackLinks_" <> entrypoint
|
||||
let entryName = mkName $ "bundlerEntrypoint_" <> entrypoint
|
||||
widgetName = mkName $ "bundlerLinks_" <> entrypoint
|
||||
|
||||
staticR <- newName "staticR"
|
||||
sequence
|
||||
@ -82,16 +81,12 @@ mkWebpackEntrypoints manifest mkGen stDir = do
|
||||
| mime `ctEq` "application/javascript"
|
||||
-> addScript $ $(varE staticR) sRoute
|
||||
| otherwise
|
||||
-> $logErrorS "siteLayout" [st|Unknown mime type in webpack bundle: #{tshow mime}|]
|
||||
-> $logErrorS "siteLayout" [st|Unknown mime type in bundle: #{tshow mime}|]
|
||||
|]) []
|
||||
]
|
||||
]
|
||||
where
|
||||
decodeManifest :: FilePath -> Q (Map String [FilePath])
|
||||
decodeManifest manifest' = do
|
||||
res <- liftIO $ Yaml.decodeFileWithWarnings manifest'
|
||||
case res of
|
||||
Left exc -> throwM exc
|
||||
Right (ws, res') -> res' <$ mapM_ (\w -> reportWarning $ "Warning while parsing webpack manifest: " <> show w) ws
|
||||
|
||||
|
||||
decodeManifest :: FilePath -> Q (Map String (Map String FilePath))
|
||||
decodeManifest manifest' = liftIO (Aeson.eitherDecodeFileStrict manifest') >>= \case
|
||||
Left exc -> error $ "Encountered error while decoding manifest: " ++ exc
|
||||
Right res -> return res
|
||||
@ -1,4 +1,4 @@
|
||||
-- SPDX-FileCopyrightText: 2022 Gregor Kleen <gregor.kleen@ifi.lmu.de>
|
||||
-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor.kleen@ifi.lmu.de>
|
||||
--
|
||||
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
@ -58,7 +58,7 @@ nwellKnownHtmlLinks = mkName "wellKnownHtmlLinks"
|
||||
|
||||
mkWellKnown :: Lang -- ^ Default language
|
||||
-> FilePath -- ^ Base directory
|
||||
-> FilePath -- ^ Link file (@html_code.html@)
|
||||
-> FilePath -- ^ Link file (@include.html@)
|
||||
-> DecsQ
|
||||
mkWellKnown defLang wellKnownBase wellKnownLinks = do
|
||||
inputFiles <- fmap dirTree . liftIO $ readDirectoryWith (\f -> (f, ) <$> BS.readFile f) wellKnownBase
|
||||
@ -79,7 +79,7 @@ mkWellKnown defLang wellKnownBase wellKnownLinks = do
|
||||
return $ file & _1 %~ makeRelative (wellKnownBase </> language)
|
||||
return (Text.pack language, lContents')
|
||||
| otherwise
|
||||
-> fail "wellKnownBase is not a directory"
|
||||
-> fail "well-known does not exist or is not a directory"
|
||||
|
||||
fLanguages <- if
|
||||
| defLang `Set.member` Map.keysSet languageFiles
|
||||
@ -103,7 +103,7 @@ mkWellKnown defLang wellKnownBase wellKnownLinks = do
|
||||
c <- lContents'
|
||||
return (Text.pack language, c)
|
||||
| otherwise
|
||||
-> fail "wellKnownBase is not a directory"
|
||||
-> fail "well-known does not exist or is not a directory"
|
||||
|
||||
lLanguages <- if
|
||||
| defLang `Set.member` Map.keysSet languageLinks
|
||||
|
||||
Loading…
Reference in New Issue
Block a user