mirror of
https://github.com/MichaByte/OnBoard-Live.git
synced 2025-12-06 07:13:41 -05:00
50% done with submission flow i think
This commit is contained in:
parent
f57c38250a
commit
25dbca5c56
7 changed files with 218 additions and 44 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
@ -5,21 +7,16 @@ from random import choice
|
||||||
from secrets import token_hex
|
from secrets import token_hex
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
import fastapi
|
|
||||||
import httpx
|
import httpx
|
||||||
|
import uvicorn
|
||||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
from apscheduler.triggers.interval import IntervalTrigger
|
from apscheduler.triggers.interval import IntervalTrigger
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from fastapi import FastAPI, Request, Response
|
from fastapi import FastAPI, HTTPException, Request, Response
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi_oauth2.claims import Claims
|
|
||||||
from fastapi_oauth2.client import OAuth2Client
|
|
||||||
from fastapi_oauth2.config import OAuth2Config
|
|
||||||
from prisma import Prisma
|
from prisma import Prisma
|
||||||
from slack_bolt.adapter.fastapi.async_handler import AsyncSlackRequestHandler
|
from slack_bolt.adapter.fastapi.async_handler import AsyncSlackRequestHandler
|
||||||
from slack_bolt.async_app import AsyncAck, AsyncApp
|
from slack_bolt.async_app import AsyncAck, AsyncApp
|
||||||
from social_core.backends.slack import SlackOAuth2
|
|
||||||
import uvicorn
|
|
||||||
|
|
||||||
load_dotenv(dotenv_path="./.env")
|
load_dotenv(dotenv_path="./.env")
|
||||||
|
|
||||||
|
|
@ -28,19 +25,27 @@ active_streams: List[Dict[str, str | bool]] = []
|
||||||
|
|
||||||
scheduler = AsyncIOScheduler()
|
scheduler = AsyncIOScheduler()
|
||||||
|
|
||||||
oauth2_config = OAuth2Config(
|
|
||||||
allow_http=False,
|
def verify_gh_signature(payload_body, secret_token, signature_header):
|
||||||
jwt_secret=os.environ["JWT_SECRET"],
|
"""Verify that the payload was sent from GitHub by validating SHA256.
|
||||||
jwt_expires=os.environ["JWT_EXPIRES"],
|
|
||||||
jwt_algorithm=os.environ["JWT_ALGORITHM"],
|
Raise and return 403 if not authorized.
|
||||||
clients=[
|
|
||||||
OAuth2Client(
|
Args:
|
||||||
backend=SlackOAuth2,
|
payload_body: original request body to verify (request.body())
|
||||||
client_id=os.environ["SLACK_TOKEN"],
|
secret_token: GitHub app webhook token (WEBHOOK_SECRET)
|
||||||
client_secret=os.environ["SLACK_SIGNING_SECRET"],
|
signature_header: header received from GitHub (x-hub-signature-256)
|
||||||
|
"""
|
||||||
|
if not signature_header:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403, detail="x-hub-signature-256 header is missing!"
|
||||||
)
|
)
|
||||||
],
|
hash_object = hmac.new(
|
||||||
)
|
secret_token.encode("utf-8"), msg=payload_body, digestmod=hashlib.sha256
|
||||||
|
)
|
||||||
|
expected_signature = "sha256=" + hash_object.hexdigest()
|
||||||
|
if not hmac.compare_digest(expected_signature, signature_header):
|
||||||
|
raise HTTPException(status_code=403, detail="Request signatures didn't match!")
|
||||||
|
|
||||||
|
|
||||||
async def update_active():
|
async def update_active():
|
||||||
|
|
@ -75,17 +80,13 @@ async def update_active():
|
||||||
)
|
)
|
||||||
new_stream = choice(active_streams)
|
new_stream = choice(active_streams)
|
||||||
print(f"found new stream to make active: {new_stream}")
|
print(f"found new stream to make active: {new_stream}")
|
||||||
try:
|
|
||||||
await db.connect()
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
print(f"trying to find user associated with stream {active_stream['name']}")
|
print(f"trying to find user associated with stream {active_stream['name']}")
|
||||||
old_active_stream_user = await db.user.find_first(where={"id": (await db.stream.find_first(where={"key": str(active_stream["name"])})).user_id}) # type: ignore
|
old_active_stream_user = await db.user.find_first(where={"id": (await db.stream.find_first(where={"key": str(active_stream["name"])})).user_id}) # type: ignore
|
||||||
await bolt.client.chat_postMessage(channel="C07ERCGG989", text=f"Hey <@{old_active_stream_user.slack_id}>, you're no longer in focus!") # type: ignore
|
await bolt.client.chat_postMessage(channel="C07ERCGG989", text=f"Hey <@{old_active_stream_user.slack_id}>, you're no longer in focus!") # type: ignore
|
||||||
active_stream = new_stream
|
active_stream = new_stream
|
||||||
active_stream_user = await db.user.find_first(where={"id": (await db.stream.find_first(where={"key": str(active_stream["name"])})).user_id}) # type: ignore
|
active_stream_user = await db.user.find_first(where={"id": (await db.stream.find_first(where={"key": str(active_stream["name"])})).user_id}) # type: ignore
|
||||||
await bolt.client.chat_postMessage(channel="C07ERCGG989", text=f"Hey <@{active_stream_user.slack_id}>, you're in focus! Make sure to tell us what you're working on!") # type: ignore
|
await bolt.client.chat_postMessage(channel="C07ERCGG989", text=f"Hey <@{active_stream_user.slack_id}>, you're in focus! Make sure to tell us what you're working on!") # type: ignore
|
||||||
await db.disconnect()
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def check_for_new():
|
async def check_for_new():
|
||||||
|
|
@ -124,19 +125,16 @@ async def lifespan(app: FastAPI):
|
||||||
scheduler.start()
|
scheduler.start()
|
||||||
scheduler.add_job(update_active, IntervalTrigger(seconds=5 * 60))
|
scheduler.add_job(update_active, IntervalTrigger(seconds=5 * 60))
|
||||||
scheduler.add_job(check_for_new, IntervalTrigger(seconds=3))
|
scheduler.add_job(check_for_new, IntervalTrigger(seconds=3))
|
||||||
try:
|
await db.connect()
|
||||||
await db.connect()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
for stream in await db.stream.find_many():
|
for stream in await db.stream.find_many():
|
||||||
await client.post(
|
await client.post(
|
||||||
"http://127.0.0.1:9997/v3/config/paths/add/" + stream.key,
|
"http://127.0.0.1:9997/v3/config/paths/add/" + stream.key,
|
||||||
json={"name": stream.key},
|
json={"name": stream.key},
|
||||||
)
|
)
|
||||||
await db.disconnect()
|
|
||||||
yield
|
yield
|
||||||
scheduler.shutdown()
|
scheduler.shutdown()
|
||||||
|
await db.disconnect()
|
||||||
|
|
||||||
|
|
||||||
api = FastAPI(lifespan=lifespan) # type: ignore
|
api = FastAPI(lifespan=lifespan) # type: ignore
|
||||||
|
|
@ -157,11 +155,48 @@ bolt = AsyncApp(
|
||||||
bolt_handler = AsyncSlackRequestHandler(bolt)
|
bolt_handler = AsyncSlackRequestHandler(bolt)
|
||||||
|
|
||||||
|
|
||||||
|
@api.post("/api/v1/github/pr_event")
|
||||||
|
async def pr_event(request: Request):
|
||||||
|
verify_gh_signature(
|
||||||
|
await request.body(),
|
||||||
|
os.environ["GH_HOOK_SECRET"],
|
||||||
|
request.headers.get("x-hub-signature-256"),
|
||||||
|
)
|
||||||
|
body = json.loads(await request.body())
|
||||||
|
if body["action"] == "labeled":
|
||||||
|
if body["label"]["id"] == 7336079497:
|
||||||
|
print("Added label has same id as OBL label!")
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
db_pr = await db.pullrequest.create({"github_id": body["number"]})
|
||||||
|
db_pr_token = db_pr.token
|
||||||
|
await client.post(
|
||||||
|
f"https://api.github.com/repos/hackclub/OnBoard/issues/{body["issue"]["number"]}/comments",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"token {os.environ['GH_TOKEN']}",
|
||||||
|
"Accept": "application/vnd.github.v3+json",
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"body": f"Hey, I'm Micha, a.k.a `@mra` on Slack! It looks like this is an OnBoard Live submission. If that sounds right, then go to the #onboard-live channel on Slack and send the message `/onboard-live-submit {db_pr_token}`. Doing that helps us link this pull request to your Slack account lets you select your sessions for review.\n###### If you have no clue what OnBoard Live is, please disregard this automated message!"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif "created" in body and "comment" in body:
|
||||||
|
if body["comment"]["user"]["id"] == body["issue"]["user"]["id"]:
|
||||||
|
db_pr = await db.pullrequest.find_first(where={"github_id": body["issue"]["number"]})
|
||||||
|
if db_pr:
|
||||||
|
if db_pr.possible_users:
|
||||||
|
for user in db_pr.possible_users:
|
||||||
|
if hashlib.sha256(bytes(f"{db_pr.secondary_token}+{user.slack_id}", encoding="utf-8")).hexdigest() in body["comment"]["body"]:
|
||||||
|
# Yay, the user who ran the Slack submit command is the same user who submitted the PR!
|
||||||
|
db_pr.user = user
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("possible users was none")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
@api.get("/api/v1/stream_key/{stream_key}")
|
@api.get("/api/v1/stream_key/{stream_key}")
|
||||||
async def get_stream_by_key(stream_key: str):
|
async def get_stream_by_key(stream_key: str):
|
||||||
await db.connect()
|
|
||||||
stream = await db.stream.find_first(where={"key": stream_key})
|
stream = await db.stream.find_first(where={"key": stream_key})
|
||||||
await db.disconnect()
|
|
||||||
return (
|
return (
|
||||||
stream if stream else Response(status_code=404, content="404: Stream not found")
|
stream if stream else Response(status_code=404, content="404: Stream not found")
|
||||||
)
|
)
|
||||||
|
|
@ -220,10 +255,6 @@ async def deny(ack, body):
|
||||||
@bolt.action("approve")
|
@bolt.action("approve")
|
||||||
async def approve(ack, body):
|
async def approve(ack, body):
|
||||||
await ack()
|
await ack()
|
||||||
try:
|
|
||||||
await db.connect()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
message = body["message"]
|
message = body["message"]
|
||||||
applicant_slack_id = message["blocks"][len(message) - 3]["text"]["text"].split(
|
applicant_slack_id = message["blocks"][len(message) - 3]["text"]["text"].split(
|
||||||
": "
|
": "
|
||||||
|
|
@ -262,7 +293,6 @@ async def approve(ack, body):
|
||||||
channel=sumbitter_convo["channel"]["id"],
|
channel=sumbitter_convo["channel"]["id"],
|
||||||
text=f"Welcome to OnBoard Live! Your stream key is {new_stream.key}. To use your stream key the easy way, go to <https://live.onboard.hackclub.com/{new_stream.key}/publish|this link>. You can also use it in OBS with the server URL of rtmp://live.onboard.hackclub.com:1935",
|
text=f"Welcome to OnBoard Live! Your stream key is {new_stream.key}. To use your stream key the easy way, go to <https://live.onboard.hackclub.com/{new_stream.key}/publish|this link>. You can also use it in OBS with the server URL of rtmp://live.onboard.hackclub.com:1935",
|
||||||
)
|
)
|
||||||
await db.disconnect()
|
|
||||||
|
|
||||||
|
|
||||||
@bolt.view("apply")
|
@bolt.view("apply")
|
||||||
|
|
@ -287,9 +317,6 @@ async def handle_application_submission(ack, body):
|
||||||
channel=sumbitter_convo["channel"]["id"],
|
channel=sumbitter_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, or you forgot something in your application, please message <@{os.environ['ADMIN_SLACK_ID']}>! Here's a copy of your responses for your reference:\nSome info on your project(s): {body['view']['state']['values']['project-info']['project-info-body']['value']}\n{f'Please fill out <https://forms.hackclub.com/eligibility?program=Onboard%20Live&slack_id={user}|the verification form>! We can only approve your application once this is done.' if not user_verified else ''}",
|
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, or you forgot something in your application, please message <@{os.environ['ADMIN_SLACK_ID']}>! Here's a copy of your responses for your reference:\nSome info on your project(s): {body['view']['state']['values']['project-info']['project-info-body']['value']}\n{f'Please fill out <https://forms.hackclub.com/eligibility?program=Onboard%20Live&slack_id={user}|the verification form>! We can only approve your application once this is done.' if not user_verified else ''}",
|
||||||
)
|
)
|
||||||
admin_convo = await bolt.client.conversations_open(
|
|
||||||
users=os.environ["ADMIN_SLACK_ID"], return_im=True
|
|
||||||
)
|
|
||||||
will_behave = True
|
will_behave = True
|
||||||
# boxes = body["view"]["state"]["values"]["kAgeY"]["checkboxes"]["selected_options"]
|
# boxes = body["view"]["state"]["values"]["kAgeY"]["checkboxes"]["selected_options"]
|
||||||
# if len(boxes) == 1 and boxes[0]["value"] == "value-1":
|
# if len(boxes) == 1 and boxes[0]["value"] == "value-1":
|
||||||
|
|
@ -376,6 +403,29 @@ async def handle_application_submission(ack, body):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bolt.command("/onboard-live-submit")
|
||||||
|
async def submit(ack: AsyncAck, command):
|
||||||
|
await ack()
|
||||||
|
user_id = command["user_id"]
|
||||||
|
channel_id = command["channel_id"]
|
||||||
|
text = command["text"]
|
||||||
|
db_pr = await db.pullrequest.find_first(where={"token": text})
|
||||||
|
db_user = await db.user.find_first_or_raise(where={"slack_id": user_id})
|
||||||
|
if db_pr is None:
|
||||||
|
await bolt.client.chat_postEphemeral(
|
||||||
|
channel=channel_id,
|
||||||
|
user=user_id,
|
||||||
|
text="There doesn't seem to be a PR open with that token! If this seems like a mistake, please message <@U05C64XMMHV> about it!",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
await db.pullrequest.update(where={"id": db_pr.id}, data={"possible_users": {"set": [{"id": db_user.id}]}})
|
||||||
|
await bolt.client.chat_postEphemeral(
|
||||||
|
channel=channel_id,
|
||||||
|
user=user_id,
|
||||||
|
text=f"Please go to <https://github.com/hackclub/OnBoard/pull/{db_pr.github_id}|your pull request> and add a comment containing the secret code `{hashlib.sha256(bytes(f"{db_pr.secondary_token}+{user_id}", encoding="utf-8")).hexdigest()}`. This helps us make sure this is your PR!",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bolt.command("/onboard-live-apply")
|
@bolt.command("/onboard-live-apply")
|
||||||
async def apply(ack: AsyncAck, command):
|
async def apply(ack: AsyncAck, command):
|
||||||
await ack()
|
await ack()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "PullRequest" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "PullRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_token_key" ON "PullRequest"("token");
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_PullRequest" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"userId" TEXT,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "PullRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_PullRequest" ("id", "token", "userId") SELECT "id", "token", "userId" FROM "PullRequest";
|
||||||
|
DROP TABLE "PullRequest";
|
||||||
|
ALTER TABLE "new_PullRequest" RENAME TO "PullRequest";
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_token_key" ON "PullRequest"("token");
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `github_id` to the `PullRequest` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_PullRequest" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"github_id" INTEGER NOT NULL,
|
||||||
|
"userId" TEXT,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "PullRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_PullRequest" ("id", "token", "userId") SELECT "id", "token", "userId" FROM "PullRequest";
|
||||||
|
DROP TABLE "PullRequest";
|
||||||
|
ALTER TABLE "new_PullRequest" RENAME TO "PullRequest";
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_github_id_key" ON "PullRequest"("github_id");
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_token_key" ON "PullRequest"("token");
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The required column `secondary_token` was added to the `PullRequest` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_PullRequest" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"github_id" INTEGER NOT NULL,
|
||||||
|
"userId" TEXT,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"secondary_token" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "PullRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_PullRequest" ("github_id", "id", "token", "userId") SELECT "github_id", "id", "token", "userId" FROM "PullRequest";
|
||||||
|
DROP TABLE "PullRequest";
|
||||||
|
ALTER TABLE "new_PullRequest" RENAME TO "PullRequest";
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_github_id_key" ON "PullRequest"("github_id");
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_token_key" ON "PullRequest"("token");
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_secondary_token_key" ON "PullRequest"("secondary_token");
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `userId` on the `PullRequest` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "_PullRequestToPossibleUser" (
|
||||||
|
"A" INTEGER NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "_PullRequestToPossibleUser_A_fkey" FOREIGN KEY ("A") REFERENCES "PullRequest" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT "_PullRequestToPossibleUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_PullRequest" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"github_id" INTEGER NOT NULL,
|
||||||
|
"known_user_id" TEXT,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"secondary_token" TEXT NOT NULL,
|
||||||
|
CONSTRAINT "PullRequest_known_user_id_fkey" FOREIGN KEY ("known_user_id") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_PullRequest" ("github_id", "id", "secondary_token", "token") SELECT "github_id", "id", "secondary_token", "token" FROM "PullRequest";
|
||||||
|
DROP TABLE "PullRequest";
|
||||||
|
ALTER TABLE "new_PullRequest" RENAME TO "PullRequest";
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_github_id_key" ON "PullRequest"("github_id");
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_token_key" ON "PullRequest"("token");
|
||||||
|
CREATE UNIQUE INDEX "PullRequest_secondary_token_key" ON "PullRequest"("secondary_token");
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "_PullRequestToPossibleUser_AB_unique" ON "_PullRequestToPossibleUser"("A", "B");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "_PullRequestToPossibleUser_B_index" ON "_PullRequestToPossibleUser"("B");
|
||||||
|
|
@ -10,11 +10,13 @@ datasource db {
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
created_at DateTime @default(now())
|
created_at DateTime @default(now())
|
||||||
slack_id String @unique
|
slack_id String @unique
|
||||||
name String
|
name String
|
||||||
stream Stream?
|
stream Stream?
|
||||||
|
possible_pulls PullRequest[] @relation(name: "PullRequestToPossibleUser") // pull requests that this user has tried to claim via the /onboard-live-submit command on Slack
|
||||||
|
known_pulls PullRequest[] @relation(name: "PullRequestToKnownUser") // pull requests that have been verified to belong to this user
|
||||||
}
|
}
|
||||||
|
|
||||||
model Stream {
|
model Stream {
|
||||||
|
|
@ -26,3 +28,13 @@ model Stream {
|
||||||
user_id String @unique
|
user_id String @unique
|
||||||
user User @relation(fields: [user_id], references: [id])
|
user User @relation(fields: [user_id], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model PullRequest {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
github_id Int @unique
|
||||||
|
user User? @relation(name: "PullRequestToKnownUser", fields: [known_user_id], references: [id])
|
||||||
|
known_user_id String?
|
||||||
|
token String @unique @default(uuid())
|
||||||
|
secondary_token String @unique @default(uuid())
|
||||||
|
possible_users User[] @relation(name: "PullRequestToPossibleUser")
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue