diff --git a/.gitignore b/.gitignore index e10a53c..2ec5834 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* - # environment variables .env .env.production @@ -23,3 +22,6 @@ pnpm-debug.log* # Local Netlify folder .netlify + +# seed file +db/seed.ts diff --git a/auth.config.mjs b/auth.config.mjs index e61cd6c..024d8ca 100644 --- a/auth.config.mjs +++ b/auth.config.mjs @@ -1,101 +1,107 @@ import Slack from "@auth/core/providers/slack"; import { defineConfig } from "auth-astro"; -import { db, like, User, Organization } from "astro:db"; +import { db, like, and, User, Organization } from "astro:db"; export default defineConfig({ - providers: [ - Slack({ - clientId: import.meta.env.SLACK_CLIENT_ID, - clientSecret: import.meta.env.SLACK_CLIENT_SECRET, - checks: ["pkce", "nonce"], - async profile(profile) { - const role = await db - .select() - .from(User) - .where(like(User.userId, profile["https://slack.com/user_id"])); + providers: [ + Slack({ + clientId: import.meta.env.SLACK_CLIENT_ID, + clientSecret: import.meta.env.SLACK_CLIENT_SECRET, + checks: ["pkce", "nonce"], + async profile(profile) { + profile["https://slack.com/team_id"] = + "slack-" + profile["https://slack.com/team_id"]; - if (role.length === 0) { - const users = await db - .select() - .from(User) - .where(like(User.team, profile["https://slack.com/team_id"])); + const role = await db + .select() + .from(User) + .where( + and(like(User.userId, profile["https://slack.com/user_id"])), + like(User.team, profile["https://slack.com/team_id"]) + ); - const organizations = await db - .select() - .from(Organization) - .where( - like(Organization.team, profile["https://slack.com/team_id"]), - ); + if (role.length === 0) { + const users = await db + .select() + .from(User) + .where(like(User.team, profile["https://slack.com/team_id"])); - // check if the user is part of an organization in the db by checking if the team id is the same - if ( - organizations - .map((org) => org.team) - .includes(profile["https://slack.com/team_id"]) - ) { - if (users.length === 0) { - await db.insert(User).values({ - userId: profile["https://slack.com/user_id"], - name: profile.name, - email: profile.email, - image: profile.picture, - team: profile["https://slack.com/team_id"], - role: "admin", - }); + const organizations = await db + .select() + .from(Organization) + .where( + like(Organization.team, profile["https://slack.com/team_id"]) + ); - role[0] = { role: "admin" }; - } else { - await db.insert(User).values({ - userId: profile["https://slack.com/user_id"], - name: profile.name, - email: profile.email, - image: profile.picture, - team: profile["https://slack.com/team_id"], - role: "user", - }); + // check if the user is part of an organization in the db by checking if the team id is the same + if ( + organizations + .map((org) => org.team) + .includes(profile["https://slack.com/team_id"]) + ) { + if (users.length === 0) { + await db.insert(User).values({ + userId: profile["https://slack.com/user_id"], + name: profile.name, + email: profile.email, + image: profile.picture, + team: profile["https://slack.com/team_id"], + role: "admin", + }); - role[0] = { role: "user" }; - } - } else { - role[0] = { role: "guest" }; - } - } + role[0] = { role: "admin" }; + } else { + await db.insert(User).values({ + userId: profile["https://slack.com/user_id"], + name: profile.name, + email: profile.email, + image: profile.picture, + team: profile["https://slack.com/team_id"], + role: "user", + }); - return { - id: profile["https://slack.com/user_id"], - name: profile.name, - email: profile.email, - image: profile.picture, - team: profile["https://slack.com/team_id"], - teamName: profile["https://slack.com/team_name"], - teamImage: profile["https://slack.com/team_image_230"], - role: role[0].role || "user", - }; - }, - }), - ], - callbacks: { - jwt({ token, user }) { - if (user) { - // User is available during sign-in - token.team = user.team; - token.teamName = user.teamName; - token.teamImage = user.teamImage; - token.role = user.role; - token.id = user.id; - } - return token; - }, - session({ session, token }) { - if (token) { - // Token is available during sign-in - session.team = token.team; - session.teamName = token.teamName; - session.teamImage = token.teamImage; - session.user.role = token.role; - session.user.id = token.id; - } - return session; - }, - }, + role[0] = { role: "user" }; + } + } else { + role[0] = { role: "guest" }; + } + } + + return { + id: profile["https://slack.com/user_id"], + name: profile.name, + email: profile.email, + image: profile.picture, + team: profile["https://slack.com/team_id"], + teamName: profile["https://slack.com/team_name"], + teamImage: profile["https://slack.com/team_image_230"], + role: role[0].role || "user", + }; + }, + }), + ], + callbacks: { + jwt({ token, user }) { + if (user) { + // User is available during sign-in + token.team = user.team; + token.teamName = user.teamName; + token.teamImage = user.teamImage; + token.role = user.role; + token.id = user.id; + } + return token; + }, + session({ session, token }) { + if (token) { + // Token is available during sign-in + session.team = token.team; + session.teamName = token.teamName; + session.teamImage = token.teamImage; + session.user.role = token.role; + session.user.id = token.id; + } + return session; + }, + }, }); diff --git a/bun.lockb b/bun.lockb index d2c75c2..048c98c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/db/config.ts b/db/config.ts index 7ba75b4..7a382e3 100644 --- a/db/config.ts +++ b/db/config.ts @@ -5,6 +5,7 @@ const Organization = defineTable({ team: column.text({ primaryKey: true }), name: column.text(), image: column.text(), + lastMessageHash: column.text({ optional: true, default: "" }), }, indexes: { teamx: { on: ["team"], unique: true }, diff --git a/db/seed.ts b/db/seed.ts deleted file mode 100644 index ca2bded..0000000 --- a/db/seed.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { db, Invite, Event, Organization } from "astro:db"; - -// https://astro.build/db/seed -export default async function seed() { - await db.insert(Organization).values([ - { - team: "T0266FRGM", - name: "Hack Club", - image: - "https://avatars.slack-edge.com/2022-04-01/3330920659891_26353517af684373601b_230.png", - }, - ]); - await db.insert(Event).values([ - { - team: "T0266FRGM", - name: "Hackclub Meeting", - comments: "This is a test event", - date: new Date(), - location: "Some location", - statusGoing: "", - statusMaybe: "", - statusNotGoing: "U062UG485EE", - }, - ]); - - await db.insert(Invite).values([ - { - verificationCode: "123456", - teamName: "Hack Club", - installationToken: "xoxb-123456", - }, - ]); -} diff --git a/package.json b/package.json index ce2897d..b96307e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "prettier": "^3.2.5", "prettier-plugin-astro": "^0.13.0", "tailwindcss": "^3.4.2", + "ts-md5": "^1.3.1", "typescript": "^5.4.3" }, "devDependencies": { diff --git a/src/components/AuthContainer.astro b/src/components/AuthContainer.astro index ba7e411..07afb07 100644 --- a/src/components/AuthContainer.astro +++ b/src/components/AuthContainer.astro @@ -47,6 +47,16 @@ type ExtendedSession = { Settings + { + session.user.role == "admin" ? ( + <> + /{" "} + + Messages + + + ) : null + } diff --git a/src/pages/api/remind.ts b/src/pages/api/remind.ts new file mode 100644 index 0000000..d90005d --- /dev/null +++ b/src/pages/api/remind.ts @@ -0,0 +1,31 @@ +import type { APIRoute } from "astro" +import { db, User, Organization, Event } from "astro:db"; + +export const POST: APIRoute = async ({ request }) => { + // get authorization header + const auth = request.headers.get("Authorization") + + if (auth === process.env.API_SECRET) { + const events = await db.select().from(Event) + const users = await db.select().from(User) + const organizations = await db.select().from(Organization) + + console.log(`Found ${events.length} events and ${users.length} users`) + + const eventsHappeningToday = events.filter((e) => { + const eventDate = new Date(e.date) + const now = new Date() + const diff = eventDate.getTime() - now.getTime() + const diffHours = diff / (1000 * 60 * 60) + return diffHours < 24 && diffHours > 0 + }) + + return new Response(JSON.stringify({ + ok: true, eventsHappeningToday: eventsHappeningToday, users: users, organizations: organizations + }), { status: 200 }) + } else { + return new Response(JSON.stringify({ + ok: false, error: "Unauthorized" + }), { status: 401 }) + } +} \ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index b908eb0..ee10a67 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -52,19 +52,13 @@ import AuthContainer from "../components/AuthContainer.astro"; Sign-in with Slack - Allows you to sign in with slack and auto asigns admins based on - slack admin status. + Allows you to sign in with Slack! Fully Functional! Team Creation Allows you to create a team and add team members. - Fully functional but currently a manual process; working on - transitioning to a auto invite system + Fully functional! Event Scheduling @@ -75,12 +69,20 @@ import AuthContainer from "../components/AuthContainer.astro"; Team Management Allows teams to manage their team members and roles. - WIP - Active Progress + Fully Functional + + + Team Annoucements + Allows teams to make announcements to their team members via + email. + Finished! FRC Dashboard Integration Enable easy adding of team members to your FRC Dashboard! - Next up after team management + WIP diff --git a/src/pages/join/[joinCode].astro b/src/pages/join/[joinCode].astro index 314ffaa..85c628c 100644 --- a/src/pages/join/[joinCode].astro +++ b/src/pages/join/[joinCode].astro @@ -85,17 +85,17 @@ if (session && session.user.role === "guest") {

Thanks for signing your team {team.teamName} up for MagicSnap! To - get started, you'll need to connect your Slack workspace to - MagicSnap. This will allow us to enable sign-in with Slack, and to - access your team's profile information. + get started, you'll need to connect your workspace to MagicSnap. + This will allow us to enable OAuth sign-in, and to access your + team's profile information.

-
+
- Connect your Slack Workspace + Connect your workspace
@@ -107,12 +107,11 @@ if (session && session.user.role === "guest") {

You have successfully connected your team {team.teamName} to - MagicSnap! You can now sign in to MagicSnap using your Slack account - and you will be redirected to your team's dashboard as the team - owner. + MagicSnap! You can now sign in to MagicSnap using your account and + you will be redirected to your team's dashboard as the team owner.

-
+