import { gql } from "https://deno.land/x/graphql_tag@0.0.1/mod.ts"
import * as bcrypt from "https://deno.land/x/bcrypt@v0.4.1/mod.ts"
const gqlApi = "http://localhost:4185/dbs/<TODO>/graphql"
interface User {
id: number
email: string
name: string
password_hash?: string
}
async function saveUserWithToken (user: User, token: string) {
const response = await fetch(gqlApi, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
mutation UpdateSessionToken(
$user: users_set_input!,
$usersFilter: users_filter!
) {
update_users(filter: $usersFilter, set: $user) {
affected_rows
}
}
`,
variables: {
usersFilter: {
email: {
eq: user.email,
},
},
user: {
email: user.email,
session_token: token,
},
},
})
})
if (response.ok) {
return { data: { sessionToken: token } }
}
else {
return { errors: [ {message: "Failed to save session" } ] }
}
}
async function loadUserFromToken(bearerToken: string): Promise<User | null> {
const token = bearerToken.replace(/^Bearer /, "")
const response = await fetch(gqlApi,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query GetUserForToken($userFilter: users_filter) {
users(filter: $userFilter) {
rowid
email
first_name
last_name
session_token
}
}
`,
variables: {
userFilter: { session_token: { eq : token } }
},
})
},
)
if (response.ok) {
const jsonResponse = await response.json()
const user = jsonResponse.data?.users?.[0]
if (user) {
user.id = user.rowid
user.name = user.first_name + " " + user.last_name
delete user.session_token
return user
}
}
else {
console.error(response)
}
return null
}
async function loadUsers(): Promise<User[]> {
const response = await fetch(gqlApi, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({query: `
query GetUsers {
users {
email
password_hash
}
}
`})
})
if (response.ok) {
const jsonResponse = await response.json()
return jsonResponse?.data?.users
}
else {
console.error(response)
return []
}
}
interface GQLResponse {
data?: Record<string, any>
errors?: { message: string }[]
}
export default async function (context): Promise<GQLResponse> {
const gqlQuery = context.data.query
const queryName = gql`${gqlQuery}`
?.definitions[0]
?.name
?.value
if (queryName === "LoginRequest") {
const argsObj = gql`${gqlQuery}`
?.definitions[0]
?.selectionSet
?.selections[0]
?.arguments
const email = argsObj
?.find(arg => arg.name.value === "email")
?.value
?.value
const password = argsObj
?.find(arg => arg.name.value === "password")
?.value
?.value
if (email && password) {
const users = await loadUsers()
const user = users.find(user => user.email === email)
if (user && bcrypt.compareSync(password, user?.password_hash)) {
user.name = ""
const randomToken = Math.random().toString(36).substring(2)
const saveResult = await saveUserWithToken(user, randomToken)
return saveResult
}
else {
return {
errors: [{
message:
"User does not exist or an incorrect password was specified",
}],
}
}
}
}
if (queryName === "UserRequest") {
return { data: await loadUserFromToken(context.headers.Authorization) }
}
const response = await fetch(gqlApi,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({query: gqlQuery})
},
)
if (response.ok) {
const jsonResponse = await response.json()
return jsonResponse
}
else {
return {
errors: [ { message: "Failed to fetch data" } ]
}
}
}