Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam McKee committed Jan 7, 2024
0 parents commit 2b06931
Show file tree
Hide file tree
Showing 73 changed files with 4,009 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.idea
docker-compose.yml
node_modules
dist
*/tsconfig.tsbuildinfo
*/lib
backend/.env
backend/public
84 changes: 84 additions & 0 deletions .github/workflows/blah.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: blah

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

concurrency: blah-ci

jobs:

verified:
runs-on: ubuntu-latest
needs:
- verify-backend
- verify-frontend
- verify-template
steps:
- uses: actions/checkout@v3
- run: echo "44.481800,-88.054413"

verify-backend:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
ports:
- 5432:5432
env:
POSTGRES_DB: eighty4
POSTGRES_USER: eighty4
POSTGRES_PASSWORD: eighty4
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: sql
run: |
sudo apt-get install -y postgresql-client
PGPASSWORD=eighty4 psql -U eighty4 -f backend/sql/v001-init-schema.sql eighty4
- name: verify
run: |
corepack enable && corepack prepare pnpm@latest --activate
pnpm i
pnpm build
pnpm test
working-directory: backend

verify-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: verify
run: |
corepack enable && corepack prepare pnpm@latest --activate
pnpm i
pnpm build
pnpm svg
working-directory: frontend

verify-template:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- name: verify
run: |
corepack enable && corepack prepare pnpm@latest --activate
pnpm i
pnpm build
pnpm test
working-directory: template
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
.idea
node_modules
tsconfig.tsbuildinfo

dist
backend/lib
backend/public
template/lib
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM node:20-alpine as build

WORKDIR /install.sh
COPY . .

RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm i
RUN pnpm --filter @eighty4/install-frontend build
RUN pnpm --filter @eighty4/install-backend build
RUN pnpm --filter @eighty4/install-backend --prod deploy dist

FROM node:20-alpine

WORKDIR /install.sh
COPY --from=build /install.sh/dist /install.sh

EXPOSE 5741

CMD ["node", "lib/Api.js"]
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# install.eighty4.tech (unfortunately not install.sh)

## todos

- preference mask-image css for color switches
- explain how screen
- flip theme toggle animation
- open graph paper animation
- #features animation
- graph paper loader animation
- lookup repository release ui
- configure binary distributions ui
- generate script
- cli auth sequence
- cli write script to local dir
10 changes: 10 additions & 0 deletions backend/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# https://github.com/settings/developers
GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""

# https://node-postgres.com/features/connecting#environment-variables
PGHOST="localhost"
PGPORT="5432"
PGDATABASE="eighty4"
PGUSER="eighty4"
PGPASSWORD="eighty4"
38 changes: 38 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@eighty4/install-backend",
"version": "0.0.1",
"private": true,
"author": "Adam McKee <[email protected]",
"license": "BSD-3-Clause",
"type": "module",
"main": "lib/Api.js",
"types": "lib/Api.d.ts",
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"dev": "tsx -r dotenv/config --watch src/Server.ts",
"build": "tsc --build --clean && tsc --build"
},
"dependencies": {
"@eighty4/install-template": "workspace:^0.0.1",
"cookie-parser": "^1.4.6",
"express": "^5.0.0-beta.1",
"pg": "^8.11.3",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.21",
"@types/pg": "^8.10.9",
"@types/uuid": "^9.0.7",
"dotenv": "^16.3.1",
"tsx": "^4.6.2",
"typescript": "^5.3.3",
"vitest": "^1.0.4"
},
"files": [
"public/**/*",
"lib/**/*",
"package.json"
]
}
22 changes: 22 additions & 0 deletions backend/sql/v001-init-schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
drop schema if exists install_sh cascade;

create schema install_sh;

create table install_sh.users
(
id bigint primary key,
email varchar not null,
access_token varchar not null,
created_when timestamp not null default now(),
authed_when timestamp not null default now()
);

create table install_sh.scripts
(
id bigserial primary key,
user_id integer not null references install_sh.users(id),
repo_owner varchar not null,
repo_name varchar not null,
template_version varchar not null,
created_when timestamp not null default now()
);
38 changes: 38 additions & 0 deletions backend/src/Database.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pg from 'pg'
import {describe, expect, it} from 'vitest'
import {saveUserLogin} from './Database.js'

const db = new pg.Pool()

const randomUserId = () => (Math.floor(Math.random() * 10000000))

describe('Database', () => {

describe('saveUserLogin', () => {
it('saves new user', async () => {
const userId = randomUserId()
const newUser = await saveUserLogin(userId, '[email protected]', 'accessToken')
expect(newUser).toBe(true)
const result = await db.query('select * from install_sh.users where id = $1', [userId])
expect(result.rows.length).toBe(1)
expect(result.rows[0].email).toBe('[email protected]')
expect(result.rows[0].access_token).toBe('accessToken')
expect(result.rows[0].authed_when).toBeDefined()
expect(result.rows[0].authed_when).toStrictEqual(result.rows[0].created_when)
})
it('saves login for existing user', async () => {
const userId = randomUserId()
let newUser = await saveUserLogin(userId, '[email protected]', 'accessToken0')
expect(newUser).toBe(true)
let result = await db.query('select * from install_sh.users where id = $1', [userId])
expect(result.rows[0].email).toBe('[email protected]')
expect(result.rows[0].access_token).toBe('accessToken0')
newUser = await saveUserLogin(userId, '[email protected]', 'accessToken1')
expect(newUser).toBe(false)
result = await db.query('select * from install_sh.users where id = $1', [userId])
expect(result.rows[0].email).toBe('[email protected]')
expect(result.rows[0].access_token).toBe('accessToken1')
expect(result.rows[0].authed_when).not.toStrictEqual(result.rows[0].created_when)
})
})
})
42 changes: 42 additions & 0 deletions backend/src/Database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pg from 'pg'
import type {Repository} from '@eighty4/install-template'

// https://node-postgres.com/features/connecting#environment-variables
const connectionPool = new pg.Pool({
max: 20,
maxUses: 1000,
})

interface GeneratedScriptParams {
userId: number
repository: Repository
templateVersion: string
}

export async function saveUserLogin(userId: number, email: string, accessToken: string): Promise<boolean> {
const result = await connectionPool.query({
name: 'save-user',
text: `
insert into install_sh.users (id, email, access_token, created_when)
values ($1, $2, $3, now())
on conflict (id) do update
set email = excluded.email,
access_token = excluded.access_token,
authed_when = now()
returning (created_when = authed_when) as new_user
`,
values: [userId, email, accessToken],
})
return result.rows[0].new_user
}

export async function saveGeneratedScript({userId, repository, templateVersion}: GeneratedScriptParams) {
await connectionPool.query({
name: 'save-script',
text: `
insert into install_sh.scripts (user_id, repo_owner, repo_name, template_version)
values ($1, $2, $3, $4)
`,
values: [userId, repository.owner, repository.name, templateVersion],
})
}
56 changes: 56 additions & 0 deletions backend/src/Login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {v4 as createUuid} from 'uuid'
import {saveUserLogin} from './Database.js'
import {fetchAccessToken, fetchEmail, fetchUserId} from './User.js'

// todo https://blog.logrocket.com/complete-guide-abortcontroller-node-js
class PromiseMap<T> {
private readonly resultById: Record<string, { timestamp: number, promise: Promise<T> }> = {}
private readonly resultByTimestamp: Array<{ id: string, timestamp: number }> = []

add(id: string, promise: Promise<T>) {
const timestamp = Date.now()
this.resultByTimestamp.push({id, timestamp})
this.resultById[id] = {timestamp, promise}
}

remove(id: string) {
delete this.resultById[id]
this.resultByTimestamp.splice(this.resultByTimestamp.findIndex((obj: any) => obj.id === id), 1)
}

resolve(id: string): Promise<T> {
const result = this.resultById[id]
this.remove(id)
if (!result) {
throw new Error('aint shit here for you')
}
return result.promise
}
}

export interface AuthedUser {
accessToken: string
newUser: boolean
}

const map = new PromiseMap<AuthedUser>()

async function loginSequence(code: string): Promise<AuthedUser> {
const accessToken = await fetchAccessToken(code)
const [email, userId] = await Promise.all([
fetchEmail(accessToken),
fetchUserId(accessToken),
])
const newUser = await saveUserLogin(userId, email, accessToken)
return {accessToken, newUser}
}

export async function initiateLogin(code: string): Promise<string> {
const loginId = createUuid()
map.add(loginId, loginSequence(code))
return loginId
}

export async function resolveLogin(loginId: string): Promise<AuthedUser> {
return map.resolve(loginId)
}
Loading

0 comments on commit 2b06931

Please sign in to comment.