commit 5ad56fac3f0b238d3db8552aa50583837369a971 Author: Micha Albert Date: Fri Jul 26 08:54:39 2024 -0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4820029 --- /dev/null +++ b/.gitignore @@ -0,0 +1,190 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +*.dat +dev.db* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2f7ff5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# OnBoard Live + +OnBoard Live is a new Hack Club You Ship, We Ship program. More details coming soon™️! diff --git a/review/README.md b/review/README.md new file mode 100644 index 0000000..50968a3 --- /dev/null +++ b/review/README.md @@ -0,0 +1,3 @@ +# Review Helpers + +This directory is a placeholder for future review automation tools! diff --git a/stream/README.md b/stream/README.md new file mode 100644 index 0000000..b3da6d1 --- /dev/null +++ b/stream/README.md @@ -0,0 +1,3 @@ +# Stream utilities + +In this folder, you'll find all the scripts, tools, and programs that are needed to operate the OnBoard Live stream. diff --git a/stream/backend/main.py b/stream/backend/main.py new file mode 100644 index 0000000..d5066bd --- /dev/null +++ b/stream/backend/main.py @@ -0,0 +1,188 @@ +from fastapi import FastAPI, Request, Response +from prisma import Prisma +from secrets import token_hex +import asyncio +from slack_bolt import Ack, App, Say +from slack_bolt.adapter.fastapi import SlackRequestHandler +from dotenv import load_dotenv +import os +import requests + +load_dotenv() + +api = FastAPI() + +db = Prisma() + +bolt = App( + token=os.environ["SLACK_TOKEN"], signing_secret=os.environ["SLACK_SIGNING_SECRET"] +) + +bolt_handler = SlackRequestHandler(bolt) + + +@bolt.event("") +@api.get("/api/v1/stream_key/{stream_key}") +async def get_stream_by_key(stream_key: str): + await db.connect() + stream = await db.stream.find_first(where={"key": stream_key}) + await db.disconnect() + return ( + stream if stream else Response(status_code=404, content="404: Stream not found") + ) + + +@api.get("/api/v1/user/{user_id}") +async def get_user_by_id(user_id: str): + await db.connect() + user = await db.user.find_first(where={"slack_id": user_id}) + await db.disconnect() + return user if user else Response(status_code=404, content="404: User not found") + + +@api.post("/api/v1/user") +async def create_user(user: dict): + await db.connect() + try: + new_user = await db.user.create( + {"slack_id": user["slack_id"], "name": user["name"]} + ) + print(new_user.id) + new_stream = await db.stream.create( + {"user": {"connect": {"id": new_user.id}}, "key": token_hex(16)} + ) + print(new_user, new_stream) + return new_user, new_stream + except Exception as e: + await db.disconnect() + return Response(status_code=500, content=f"500: {str(e)}") + finally: + await db.disconnect() + + +@bolt.event("app_home_opened") +def handle_app_home_opened_events(body, logger, event, client): + client.views_publish( + user_id=event["user"], + # the view object that appears in the app home + view={ + "type": "home", + "callback_id": "home_view", + # body of the view + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Welcome to OnBoard Live! Try sending `/onboard-live-apply` in the #onboard-live channel to get started!", + }, + }, + ], + }, + ) + + +@bolt.view("apply") +def handle_application_submission(ack, body): + ack() + print(body) + convo = bolt.client.conversations_open(users=body["user"]["id"], return_im=True) + bolt.client.chat_postMessage( + channel=convo["channel"]["id"], text=f"Your application has been submitted! We will review it shortly. Please do not send another application - If you haven't heard back in over 48 hours, message @mra! Here's a copy of your responses for your reference:\n{body['view']['state']['values']['project-info']['project-desc-value']['value']}" + ) + + +@bolt.command("/onboard-live-apply") +def apply(ack: Ack, command): + ack() + print(command) + r = requests.post( + "https://slack.com/api/views.open", + headers={"Authorization": f"Bearer {os.environ['SLACK_TOKEN']}"}, + json={ + "trigger_id": command["trigger_id"], + "view": { + "type": "modal", + "callback_id": "apply", + "title": {"type": "plain_text", "text": "Apply to OnBoard Live"}, + "submit": {"type": "plain_text", "text": "Submit!"}, + "blocks": [ + { + "type": "input", + "block_id": "project-info", + "label": { + "type": "plain_text", + "text": "Some info on your project(s)", + }, + "element": { + "type": "plain_text_input", + "multiline": True, + "action_id": "project-desc-value", + "placeholder": { + "type": "plain_text", + "text": "I'm going to make...", + }, + }, + }, + ], + }, + }, + ) + print(r.status_code, r.text) + # bolt.client.modal(channel=command['channel_id'], user=command['user_id'], text="Application form for OnBoard Live", blocks=[{ + + +# "type": "header", +# "text": { +# "type": "plain_text", +# "text": "Welcome to OnBoard Live!", +# } +# }, +# { +# "type": "section", +# "text": { +# "type": "mrkdwn", +# "text": "Before you can get designing, we need a little bit of info from you. All fields are required!" +# } +# }, +# { +# "type": "divider" +# }, +# { +# "type": "input", +# "element": { +# "type": "plain_text_input", +# "multiline": True, +# "action_id": "project_ideas_input-action", +# "placeholder": { +# "type": "plain_text", +# "text": "I want to make a..." +# } +# }, +# "label": { +# "type": "plain_text", +# "text": "What do you plan to make with OnBoard Live?\nThis can be changed anytime!", +# } +# }, +# { +# "type": "divider" +# }, +# { +# "type": "actions", +# "elements": [ +# { +# "type": "button", +# "text": { +# "type": "plain_text", +# "text": "Apply!", +# }, +# "value": "apply", +# "style": "primary", +# "action_id": "actionId-0" + +# }]}]) + + +@api.post("/slack/events") +async def slack_event_endpoint(req: Request): + return await bolt_handler.handle(req) diff --git a/stream/backend/migrations/20240719191810_init/migration.sql b/stream/backend/migrations/20240719191810_init/migration.sql new file mode 100644 index 0000000..d50c481 --- /dev/null +++ b/stream/backend/migrations/20240719191810_init/migration.sql @@ -0,0 +1,20 @@ +-- CreateTable +CREATE TABLE "Stream" ( + "id" TEXT NOT NULL PRIMARY KEY, + "key" TEXT NOT NULL, + "active" BOOLEAN NOT NULL DEFAULT false, + "focused" BOOLEAN NOT NULL DEFAULT false, + CONSTRAINT "Stream_key_fkey" FOREIGN KEY ("key") REFERENCES "User" ("slackId") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "User" ( + "slackId" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "Stream_key_key" ON "Stream"("key"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_slackId_key" ON "User"("slackId"); diff --git a/stream/backend/migrations/migration_lock.toml b/stream/backend/migrations/migration_lock.toml new file mode 100644 index 0000000..e5e5c47 --- /dev/null +++ b/stream/backend/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "sqlite" \ No newline at end of file diff --git a/stream/backend/schema.prisma b/stream/backend/schema.prisma new file mode 100644 index 0000000..a4ff3c8 --- /dev/null +++ b/stream/backend/schema.prisma @@ -0,0 +1,28 @@ +generator client { + provider = "prisma-client-py" + interface = "asyncio" + recursive_type_depth = 5 +} + +datasource db { + provider = "sqlite" + url = "file:./dev.db" +} + +model User { + id String @id @default(cuid()) + created_at DateTime @default(now()) + slack_id String @unique + name String + stream Stream? +} + +model Stream { + id String @id @default(cuid()) + created_at DateTime @default(now()) + is_live Boolean @default(false) + is_focused Boolean @default(false) + key String @unique @default(uuid()) + user User @relation(fields: [user_id], references: [id]) + user_id String @unique +} diff --git a/stream/keygen/main.py b/stream/keygen/main.py new file mode 100644 index 0000000..8d3c18a --- /dev/null +++ b/stream/keygen/main.py @@ -0,0 +1,30 @@ +import secrets +import requests +import pickle + +users = {} + +with open('users.dat', 'rb') as f: + users = pickle.load(f) + +def add_stream(stream): + requests.post('http://127.0.0.1:9997/v3/config/paths/add/' + stream, json={'name': stream}) + +def main(): + print(users) + for user in users.values(): + add_stream(user) + while True: + new_user = input('Enter new user\'s Slack ID: ') + if new_user in users: + print('User already exists.') + continue + users[new_user] = secrets.token_hex(32) + print(users[new_user]) + add_stream(users[new_user]) + with open('users.dat', 'wb') as f: + pickle.dump(users, f) + + +if __name__ == '__main__': + main() diff --git a/stream/tiling-frontend/README.md b/stream/tiling-frontend/README.md new file mode 100644 index 0000000..e6cd94f --- /dev/null +++ b/stream/tiling-frontend/README.md @@ -0,0 +1,47 @@ +# Svelte + TS + Vite + +This template should help get you started developing with Svelte and TypeScript in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). + +## Need an official Svelte framework? + +Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. + +## Technical considerations + +**Why use this over SvelteKit?** + +- It brings its own routing solution which might not be preferable for some users. +- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. + +This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. + +Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. + +**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** + +Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. + +**Why include `.vscode/extensions.json`?** + +Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. + +**Why enable `allowJs` in the TS template?** + +While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. + +**Why is HMR not preserving my local component state?** + +HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). + +If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. + +```ts +// store.ts +// An extremely simple external store +import { writable } from 'svelte/store' +export default writable(0) +``` diff --git a/stream/tiling-frontend/bun.lockb b/stream/tiling-frontend/bun.lockb new file mode 100755 index 0000000..e0a9e9a Binary files /dev/null and b/stream/tiling-frontend/bun.lockb differ diff --git a/stream/tiling-frontend/index.html b/stream/tiling-frontend/index.html new file mode 100644 index 0000000..b6c5f0a --- /dev/null +++ b/stream/tiling-frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + Svelte + TS + + +
+ + + diff --git a/stream/tiling-frontend/package.json b/stream/tiling-frontend/package.json new file mode 100644 index 0000000..f2b1860 --- /dev/null +++ b/stream/tiling-frontend/package.json @@ -0,0 +1,26 @@ +{ + "name": "onboard-plus-sfa", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.1.1", + "@tsconfig/svelte": "^5.0.4", + "svelte": "^4.2.18", + "svelte-check": "^3.8.1", + "tslib": "^2.6.3", + "typescript": "^5.2.2", + "vite": "^5.3.1" + }, + "dependencies": { + "hls.js": "^1.5.13", + "unocss": "^0.61.3", + "vite-plugin-singlefile": "^2.0.2" + } +} diff --git a/stream/tiling-frontend/public/flag-orpheus-left.svg b/stream/tiling-frontend/public/flag-orpheus-left.svg new file mode 100644 index 0000000..88ba938 --- /dev/null +++ b/stream/tiling-frontend/public/flag-orpheus-left.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/stream/tiling-frontend/src/App.svelte b/stream/tiling-frontend/src/App.svelte new file mode 100644 index 0000000..272c917 --- /dev/null +++ b/stream/tiling-frontend/src/App.svelte @@ -0,0 +1,187 @@ + + +
+
+
+

+ OnBoard Live Design Stream +

+ Hack Club + {#if pathData?.map((path) => path.ready).includes(true)} +
+ {#each pathData as path} + {#if path.ready} + + + {/if} + {/each} +
+ {:else} +
+

+ No one is here yet!
Check back later +

+
+ {/if} +

+ Join at
+ https://hack.club/onboard-live +
+

+
+ + diff --git a/stream/tiling-frontend/src/main.ts b/stream/tiling-frontend/src/main.ts new file mode 100644 index 0000000..d5f003c --- /dev/null +++ b/stream/tiling-frontend/src/main.ts @@ -0,0 +1,7 @@ +import App from './App.svelte' + +const app = new App({ + target: document.getElementById('app')!, +}) + +export default app diff --git a/stream/tiling-frontend/src/vite-env.d.ts b/stream/tiling-frontend/src/vite-env.d.ts new file mode 100644 index 0000000..4078e74 --- /dev/null +++ b/stream/tiling-frontend/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/stream/tiling-frontend/svelte.config.js b/stream/tiling-frontend/svelte.config.js new file mode 100644 index 0000000..b0683fd --- /dev/null +++ b/stream/tiling-frontend/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/stream/tiling-frontend/tsconfig.json b/stream/tiling-frontend/tsconfig.json new file mode 100644 index 0000000..7c608fc --- /dev/null +++ b/stream/tiling-frontend/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "isolatedModules": true, + "moduleDetection": "force" + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], +} diff --git a/stream/tiling-frontend/tsconfig.node.json b/stream/tiling-frontend/tsconfig.node.json new file mode 100644 index 0000000..6c2d870 --- /dev/null +++ b/stream/tiling-frontend/tsconfig.node.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "noEmit": true + }, + "include": ["vite.config.ts"] +} diff --git a/stream/tiling-frontend/vite.config.ts b/stream/tiling-frontend/vite.config.ts new file mode 100644 index 0000000..40a1bf0 --- /dev/null +++ b/stream/tiling-frontend/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import { viteSingleFile } from 'vite-plugin-singlefile'; + +export default defineConfig(({ command }) => ({ + plugins: [ + svelte({ + /* plugin options */ + }), + command === 'build' && + viteSingleFile({ + removeViteModuleLoader: true + }) + ], + build: { + minify: true + } +}));