Compare commits
No commits in common. "3b11a409288e998da03103efd900c4e69d912d51" and "45decdb1104382ff11be9486287c6edfe6c9bbda" have entirely different histories.
3b11a40928
...
45decdb110
10 changed files with 15 additions and 2445 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -38,6 +38,3 @@ database.db*
|
||||||
|
|
||||||
# graphql-codegen
|
# graphql-codegen
|
||||||
src/__generated__
|
src/__generated__
|
||||||
|
|
||||||
# NixOS
|
|
||||||
result
|
|
||||||
|
|
37
README.md
37
README.md
|
@ -50,7 +50,6 @@ After cloning, create an `.env.local` with the following contents (in `key=value
|
||||||
- `LDAP_BIND_PASSWORD`: the password of the bind user
|
- `LDAP_BIND_PASSWORD`: the password of the bind user
|
||||||
- `BASE_DOMAIN`: the domain gluestick is deployed on, with a protocol and trailing slash
|
- `BASE_DOMAIN`: the domain gluestick is deployed on, with a protocol and trailing slash
|
||||||
- This domain will be used for OAuth redirects - if you are testing locally, set it to `http://localhost:3000/`
|
- This domain will be used for OAuth redirects - if you are testing locally, set it to `http://localhost:3000/`
|
||||||
- `DATABASE_URL`: a Prisma-like path to your database
|
|
||||||
|
|
||||||
Example config:
|
Example config:
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ GITHUB_TOKEN=redacted
|
||||||
GITHUB_ORG=n2pm
|
GITHUB_ORG=n2pm
|
||||||
|
|
||||||
BASE_DOMAIN=https://gluestick.n2.pm/
|
BASE_DOMAIN=https://gluestick.n2.pm/
|
||||||
DATABASE_URL=file:./database.db
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generating code
|
### Generating code
|
||||||
|
@ -95,7 +93,7 @@ export GRAPHQL_CODEDGEN_AUTH=...
|
||||||
Then, generate the GraphQL and database code:
|
Then, generate the GraphQL and database code:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
GRAPHQL_USE_INTROSPECTION=true npm run graphql-codegen
|
npm run graphql-codegen
|
||||||
npm run prisma-generate
|
npm run prisma-generate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -110,36 +108,7 @@ npm run start
|
||||||
|
|
||||||
## Developing
|
## Developing
|
||||||
|
|
||||||
### Generating GraphQL code
|
You'll want to run these two commands at the same time:
|
||||||
|
|
||||||
Because the LLDAP GraphQL API is locked behind authentication, and of a quirk with `graphl-codegen` configuration files, we need to set a temporary environment variable to generate GraphQL code. If not using introspection, you will need a running LLDAP server.
|
|
||||||
|
|
||||||
Run the `get-token.js` helper script and set the environment variable from its output:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
node get-token.js
|
|
||||||
export GRAPHQL_CODEDGEN_AUTH=...
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, generate the GraphQL code:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm run graphql-codegen
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to use introspection, set `GRAPHQL_USE_INTROSPECTION=true` before generating the code. You won't need to set the auth environment variable in this case.
|
|
||||||
|
|
||||||
### Working with Prisma
|
|
||||||
|
|
||||||
gluestick uses [Prisma](https://www.prisma.io/) for accessing the database. If you will be modifying the database schema, you will need to work with it. Consider taking some time to familiarize yourself with the [Prisma CLI](https://www.prisma.io/docs/reference/api-reference/command-reference) first.
|
|
||||||
|
|
||||||
When first cloning, generate the Prisma client:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm run prisma-generate
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running the server
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Next.js hot reload
|
# Next.js hot reload
|
||||||
|
@ -150,3 +119,5 @@ npm run dev | pino-pretty
|
||||||
# Only required if working on GraphQL code
|
# Only required if working on GraphQL code
|
||||||
npm run graphql-codegen -- -w
|
npm run graphql-codegen -- -w
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you're interacting with the database, take some time to familiarize yourself with the [Prisma CLI](https://www.prisma.io/docs/reference/api-reference/command-reference).
|
||||||
|
|
26
codegen.ts
26
codegen.ts
|
@ -4,32 +4,24 @@ import { CodegenConfig } from "@graphql-codegen/cli";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
dotenv.config({ path: ".env.local" });
|
dotenv.config({ path: ".env.local" });
|
||||||
|
|
||||||
const useIntrospection = ["1", "true"].includes(
|
|
||||||
process.env.GRAPHQL_USE_INTROSPECTION?.toLowerCase() ?? ""
|
|
||||||
);
|
|
||||||
|
|
||||||
const config: CodegenConfig = {
|
const config: CodegenConfig = {
|
||||||
schema: useIntrospection
|
schema: {
|
||||||
? "introspection.json"
|
[`http://${process.env.LDAP_HOST}:17170/api/graphql`]: {
|
||||||
: {
|
headers: {
|
||||||
[`http://${process.env.LDAP_HOST}:17170/api/graphql`]: {
|
// can't make the request automatically (await on top level)
|
||||||
headers: {
|
Authorization: `Bearer ${process.env.GRAPHQL_CODEGEN_AUTH}`
|
||||||
// can't make the request automatically (await on top level)
|
}
|
||||||
Authorization: `Bearer ${process.env.GRAPHQL_CODEGEN_AUTH}`
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
documents: ["src/**/*.ts", "src/**/*.tsx"],
|
documents: ["src/**/*.ts", "src/**/*.tsx"],
|
||||||
generates: {
|
generates: {
|
||||||
"./src/__generated__/": {
|
"./src/__generated__/": {
|
||||||
preset: "client",
|
preset: "client",
|
||||||
|
plugins: [],
|
||||||
presetConfig: {
|
presetConfig: {
|
||||||
gqlTagName: "gql"
|
gqlTagName: "gql"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"introspection.json": {
|
|
||||||
plugins: ["introspection"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ignoreNoDocuments: true
|
ignoreNoDocuments: true
|
||||||
|
|
61
flake.lock
61
flake.lock
|
@ -1,61 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681202837,
|
|
||||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1682656005,
|
|
||||||
"narHash": "sha256-fYplYo7so1O+rSQ2/aS+SbTPwLTeoUXk4ekKNtSl4P8=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "6806b63e824f84b0f0e60b6d660d4ae753de0477",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
178
flake.nix
178
flake.nix
|
@ -1,178 +0,0 @@
|
||||||
{
|
|
||||||
description =
|
|
||||||
"NotNet's one stop shop for authentication and account onboarding";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
|
||||||
let
|
|
||||||
packages = flake-utils.lib.eachDefaultSystem (system:
|
|
||||||
let
|
|
||||||
pkgs = nixpkgs.legacyPackages."${system}";
|
|
||||||
|
|
||||||
# I really cannot be assed to pick this apart
|
|
||||||
inputs = with pkgs; [ vips pkg-config python3 ];
|
|
||||||
|
|
||||||
# https://github.com/prisma/prisma/issues/3026#issuecomment-927258138
|
|
||||||
prismaHook = with pkgs; ''
|
|
||||||
export PRISMA_MIGRATION_ENGINE_BINARY="${prisma-engines}/bin/migration-engine"
|
|
||||||
export PRISMA_QUERY_ENGINE_BINARY="${prisma-engines}/bin/query-engine"
|
|
||||||
export PRISMA_QUERY_ENGINE_LIBRARY="${prisma-engines}/lib/libquery_engine.node"
|
|
||||||
export PRISMA_INTROSPECTION_ENGINE_BINARY="${prisma-engines}/bin/introspection-engine"
|
|
||||||
export PRISMA_FMT_BINARY="${prisma-engines}/bin/prisma-fmt"
|
|
||||||
'';
|
|
||||||
in rec {
|
|
||||||
packages.gluestick = pkgs.buildNpmPackage {
|
|
||||||
pname = "gluestick";
|
|
||||||
version = "0.1.0";
|
|
||||||
src = ./.;
|
|
||||||
npmDepsHash = "sha256-keOreamXKunlJzU2AKJo0J02ZxQrjLdoCIMCaiwEU4Y=";
|
|
||||||
|
|
||||||
nativeBuildInputs = inputs;
|
|
||||||
buildInputs = inputs;
|
|
||||||
|
|
||||||
preBuild = ''
|
|
||||||
${prismaHook}
|
|
||||||
|
|
||||||
# Use the introspection.json, because we can't connect to the API at build time
|
|
||||||
GRAPHQL_USE_INTROSPECTION=true npm run graphql-codegen
|
|
||||||
npm run prisma-generate
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
mkdir -p $out
|
|
||||||
cp -r .next/standalone $out/server
|
|
||||||
cp -r .next/static $out/server/.next/static
|
|
||||||
cp -r public $out/server/public
|
|
||||||
cp -r prisma $out/prisma
|
|
||||||
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cat > $out/bin/gluestick <<EOF
|
|
||||||
#!${pkgs.stdenv.shell}
|
|
||||||
${prismaHook}
|
|
||||||
${pkgs.nodejs}/bin/node $out/server/server.js \$@
|
|
||||||
EOF
|
|
||||||
chmod +x $out/bin/gluestick
|
|
||||||
|
|
||||||
cat > $out/bin/prisma <<EOF
|
|
||||||
#!${pkgs.stdenv.shell}
|
|
||||||
${prismaHook}
|
|
||||||
|
|
||||||
${pkgs.nodePackages.prisma}/bin/prisma \$@
|
|
||||||
EOF
|
|
||||||
chmod +x $out/bin/prisma
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with pkgs.lib; {
|
|
||||||
description =
|
|
||||||
"NotNet's one stop shop for authentication and account onboarding";
|
|
||||||
homepage = "https://git.n2.pm/NotNet/gluestick";
|
|
||||||
license = licenses.mit;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
apps.gluestick = flake-utils.lib.mkApp {
|
|
||||||
name = "gluestick";
|
|
||||||
drv = packages.gluestick;
|
|
||||||
};
|
|
||||||
|
|
||||||
devShell = pkgs.mkShell {
|
|
||||||
inputsFrom = [ packages.gluestick ];
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
${prismaHook}
|
|
||||||
|
|
||||||
if [ -f .env.local ]; then
|
|
||||||
set -a
|
|
||||||
source .env.local
|
|
||||||
set +a
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
});
|
|
||||||
in packages // {
|
|
||||||
nixosModule = { config, lib, pkgs, ... }:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
cfg = config.services.gluestick;
|
|
||||||
pkg = self.packages.${pkgs.system}.gluestick;
|
|
||||||
in {
|
|
||||||
options.services.gluestick = {
|
|
||||||
enable = mkEnableOption "gluestick";
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "gluestick";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "gluestick";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 3000;
|
|
||||||
};
|
|
||||||
|
|
||||||
envFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/gluestick/.env.local";
|
|
||||||
};
|
|
||||||
|
|
||||||
databaseFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/gluestick/database.db";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
systemd.services.gluestick = {
|
|
||||||
description = "gluestick";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
|
|
||||||
preStart = ''
|
|
||||||
export DATABASE_URL="file:${cfg.databaseFile}"
|
|
||||||
${pkg}/bin/prisma migrate deploy --schema=${pkg}/prisma/schema.prisma
|
|
||||||
'';
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
export PORT=${toString cfg.port}
|
|
||||||
export NODE_ENV=production
|
|
||||||
export DATABASE_URL="file:${cfg.databaseFile}"
|
|
||||||
${pkg}/bin/gluestick
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
User = cfg.user;
|
|
||||||
Group = cfg.group;
|
|
||||||
Restart = "always";
|
|
||||||
WorkingDirectory = "/var/lib/gluestick";
|
|
||||||
EnvironmentFile = cfg.envFile;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
users = {
|
|
||||||
users = mkIf (cfg.user == "gluestick") {
|
|
||||||
gluestick = {
|
|
||||||
home = "/var/lib/gluestick";
|
|
||||||
createHome = true;
|
|
||||||
group = cfg.group;
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
groups = mkIf (cfg.group == "gluestick") { gluestick = { }; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
2123
introspection.json
2123
introspection.json
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,7 @@
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
experimental: {
|
experimental: {
|
||||||
appDir: true
|
appDir: true
|
||||||
},
|
}
|
||||||
output: "standalone"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|
26
package-lock.json
generated
26
package-lock.json
generated
|
@ -33,7 +33,6 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "^3.3.1",
|
"@graphql-codegen/cli": "^3.3.1",
|
||||||
"@graphql-codegen/client-preset": "^3.0.1",
|
"@graphql-codegen/client-preset": "^3.0.1",
|
||||||
"@graphql-codegen/introspection": "^3.0.1",
|
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.1",
|
||||||
"pino-pretty": "^10.0.0",
|
"pino-pretty": "^10.0.0",
|
||||||
"prisma": "^4.13.0"
|
"prisma": "^4.13.0"
|
||||||
|
@ -1381,20 +1380,6 @@
|
||||||
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@graphql-codegen/introspection": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-D6vJQTEL/np4EmeUHm5spLK59cr+AMXEoLRoTI+dagFzlHYDTfXZH6F7uhKaakxcj0SAQhIWKvGMggotUdEtyg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@graphql-codegen/plugin-helpers": "^4.1.0",
|
|
||||||
"@graphql-codegen/visitor-plugin-common": "^3.0.1",
|
|
||||||
"tslib": "~2.5.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@graphql-codegen/plugin-helpers": {
|
"node_modules/@graphql-codegen/plugin-helpers": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-4.2.0.tgz",
|
||||||
|
@ -9280,17 +9265,6 @@
|
||||||
"tslib": "~2.5.0"
|
"tslib": "~2.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@graphql-codegen/introspection": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-D6vJQTEL/np4EmeUHm5spLK59cr+AMXEoLRoTI+dagFzlHYDTfXZH6F7uhKaakxcj0SAQhIWKvGMggotUdEtyg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@graphql-codegen/plugin-helpers": "^4.1.0",
|
|
||||||
"@graphql-codegen/visitor-plugin-common": "^3.0.1",
|
|
||||||
"tslib": "~2.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@graphql-codegen/plugin-helpers": {
|
"@graphql-codegen/plugin-helpers": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-4.2.0.tgz",
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@graphql-codegen/cli": "^3.3.1",
|
"@graphql-codegen/cli": "^3.3.1",
|
||||||
"@graphql-codegen/client-preset": "^3.0.1",
|
"@graphql-codegen/client-preset": "^3.0.1",
|
||||||
"@graphql-codegen/introspection": "^3.0.1",
|
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.1",
|
||||||
"pino-pretty": "^10.0.0",
|
"pino-pretty": "^10.0.0",
|
||||||
"prisma": "^4.13.0"
|
"prisma": "^4.13.0"
|
||||||
|
|
|
@ -4,7 +4,7 @@ generator client {
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "sqlite"
|
||||||
url = env("DATABASE_URL")
|
url = "file:./database.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
model AuthTicket {
|
model AuthTicket {
|
||||||
|
|
Loading…
Reference in a new issue