mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-25 08:29:06 -06:00
feat(launchpad): authenticate with dashboard (#17649)
* wip: add auth * add example making authenticated request to runs * simplify template * remove cosnle * revert some files * Add test * fix buld * support logging out * test: fix ConfigFile Co-authored-by: ElevateBart <ledouxb@gmail.com>
This commit is contained in:
@@ -18,6 +18,9 @@ type App {
|
||||
|
||||
"""All known projects for the app"""
|
||||
projects: [Project!]!
|
||||
|
||||
"""Cypress Cloud"""
|
||||
user: User
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -46,9 +49,15 @@ type Mutation {
|
||||
"""Create a Cypress config file for a new project"""
|
||||
appCreateConfigFile(code: String!, configFilename: String!): App
|
||||
|
||||
"""Auth with Cypress Cloud"""
|
||||
authenticate: App
|
||||
|
||||
"""Initializes the plugins for the current active project"""
|
||||
initializePlugins: Project
|
||||
|
||||
"""Log out of Cypress Cloud"""
|
||||
logout: App
|
||||
|
||||
"""Installs the dependencies for the component testing step"""
|
||||
wizardInstallDependencies: Wizard
|
||||
|
||||
@@ -102,6 +111,12 @@ type Project {
|
||||
type Query {
|
||||
app: App!
|
||||
|
||||
"""Get runs for a given projectId on Cypress Cloud"""
|
||||
runs(projectId: String!): App
|
||||
|
||||
"""Namespace for user and authentication"""
|
||||
user: User
|
||||
|
||||
"""Metadata about the wizard, null if we arent showing the wizard"""
|
||||
wizard: Wizard
|
||||
}
|
||||
@@ -123,6 +138,13 @@ type TestingTypeInfo {
|
||||
title: String
|
||||
}
|
||||
|
||||
"""Namespace for information related to authentication with Cypress Cloud"""
|
||||
type User {
|
||||
authToken: String
|
||||
email: String
|
||||
name: String
|
||||
}
|
||||
|
||||
"""
|
||||
The Wizard is a container for any state associated with initial onboarding to Cypress
|
||||
"""
|
||||
|
||||
@@ -51,4 +51,7 @@ export abstract class BaseActions {
|
||||
}
|
||||
|
||||
abstract createProjectBase(input: NxsMutationArgs<'addProject'>['input']): ProjectBaseContract | Promise<ProjectBaseContract>
|
||||
abstract authenticate (): Promise<void>
|
||||
abstract logout (): Promise<void>
|
||||
abstract getRuns ({ projectId }: { projectId: string }): Promise<void>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { BaseActions } from '../actions/BaseActions'
|
||||
import { App, Wizard } from '../entities'
|
||||
import { App, User, Wizard } from '../entities'
|
||||
import type { Project } from '../entities/Project'
|
||||
|
||||
/**
|
||||
@@ -12,6 +12,7 @@ import type { Project } from '../entities/Project'
|
||||
export abstract class BaseContext {
|
||||
abstract readonly actions: BaseActions
|
||||
abstract projects: Project[]
|
||||
abstract user?: User = undefined
|
||||
|
||||
wizard = new Wizard()
|
||||
app = new App(this)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { nxs, NxsResult } from 'nexus-decorators'
|
||||
import type { BaseContext } from '../context/BaseContext'
|
||||
import { Project } from './Project'
|
||||
import { User } from './User'
|
||||
|
||||
@nxs.objectType({
|
||||
description: 'Namespace for information related to the app',
|
||||
@@ -28,4 +29,11 @@ export class App {
|
||||
get activeProject (): NxsResult<'App', 'activeProject'> {
|
||||
return this.projects.find((p) => p.isCurrent) ?? null
|
||||
}
|
||||
|
||||
@nxs.field.type(() => User, {
|
||||
description: 'Cypress Cloud',
|
||||
})
|
||||
get user (): NxsResult<'App', 'user'> {
|
||||
return this.ctx.user ?? null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,31 @@ export const mutation = mutationType({
|
||||
},
|
||||
})
|
||||
|
||||
t.field('authenticate', {
|
||||
type: 'App',
|
||||
description: 'Auth with Cypress Cloud',
|
||||
async resolve (_root, args, ctx) {
|
||||
// already authenticated this session - just return
|
||||
if (ctx.user) {
|
||||
return ctx.app
|
||||
}
|
||||
|
||||
await ctx.actions.authenticate()
|
||||
|
||||
return ctx.app
|
||||
},
|
||||
})
|
||||
|
||||
t.field('logout', {
|
||||
type: 'App',
|
||||
description: 'Log out of Cypress Cloud',
|
||||
async resolve (_root, args, ctx) {
|
||||
await ctx.actions.logout()
|
||||
|
||||
return ctx.app
|
||||
},
|
||||
})
|
||||
|
||||
t.field('initializePlugins', {
|
||||
type: 'Project',
|
||||
description: 'Initializes the plugins for the current active project',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { nxs, NxsQueryResult, NxsResult } from 'nexus-decorators'
|
||||
import { nxs, NxsArgs, NxsQueryResult, NxsResult } from 'nexus-decorators'
|
||||
import type { NexusGenTypes } from '../gen/nxs.gen'
|
||||
import { App } from './App'
|
||||
import { User } from './User'
|
||||
import { Wizard } from './Wizard'
|
||||
|
||||
@nxs.objectType({
|
||||
@@ -18,4 +19,23 @@ export class Query {
|
||||
wizard (args: unknown, ctx: NexusGenTypes['context']): NxsResult<'App', 'wizard'> {
|
||||
return ctx.wizard
|
||||
}
|
||||
|
||||
@nxs.field.type(() => User, {
|
||||
description: 'Namespace for user and authentication',
|
||||
})
|
||||
user (args: unknown, ctx: NexusGenTypes['context']): NxsResult<'App', 'user'> {
|
||||
return ctx.user ?? null
|
||||
}
|
||||
|
||||
@nxs.field.type(() => App, {
|
||||
description: 'Get runs for a given projectId on Cypress Cloud',
|
||||
args (t) {
|
||||
t.nonNull.string('projectId')
|
||||
},
|
||||
})
|
||||
async runs (args: NxsArgs<'Query', 'runs'>, ctx: NexusGenTypes['context']): Promise<NxsResult<'App', 'runs'>> {
|
||||
await ctx.actions.getRuns({ projectId: args.projectId })
|
||||
|
||||
return ctx.app
|
||||
}
|
||||
}
|
||||
|
||||
29
packages/graphql/src/entities/User.ts
Normal file
29
packages/graphql/src/entities/User.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { nxs, NxsResult } from 'nexus-decorators'
|
||||
|
||||
export interface AuthenticatedUser {
|
||||
name: string
|
||||
email: string
|
||||
authToken: string
|
||||
}
|
||||
|
||||
@nxs.objectType({
|
||||
description: 'Namespace for information related to authentication with Cypress Cloud',
|
||||
})
|
||||
export class User {
|
||||
constructor (private user: AuthenticatedUser) {}
|
||||
|
||||
@nxs.field.string()
|
||||
get name (): NxsResult<'User', 'name'> {
|
||||
return this.user?.name ?? null
|
||||
}
|
||||
|
||||
@nxs.field.string()
|
||||
get email (): NxsResult<'User', 'email'> {
|
||||
return this.user?.email ?? null
|
||||
}
|
||||
|
||||
@nxs.field.string()
|
||||
get authToken (): NxsResult<'User', 'authToken'> {
|
||||
return this.user?.authToken ?? null
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ export * from './Project'
|
||||
|
||||
export * from './Query'
|
||||
|
||||
export * from './User'
|
||||
|
||||
export * from './TestingTypeInfo'
|
||||
|
||||
export * from './Wizard'
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { BaseContext } from "./../context/BaseContext"
|
||||
import type { App } from "./../entities/App"
|
||||
import type { Project } from "./../entities/Project"
|
||||
import type { Query } from "./../entities/Query"
|
||||
import type { User } from "./../entities/User"
|
||||
import type { TestingTypeInfo } from "./../entities/TestingTypeInfo"
|
||||
import type { Wizard } from "./../entities/Wizard"
|
||||
import type { WizardBundler } from "./../entities/WizardBundler"
|
||||
@@ -79,6 +80,7 @@ export interface NexusGenObjects {
|
||||
Project: Project;
|
||||
Query: Query;
|
||||
TestingTypeInfo: TestingTypeInfo;
|
||||
User: User;
|
||||
Wizard: Wizard;
|
||||
WizardBundler: WizardBundler;
|
||||
WizardFrontendFramework: WizardFrontendFramework;
|
||||
@@ -100,11 +102,14 @@ export interface NexusGenFieldTypes {
|
||||
activeProject: NexusGenRootTypes['Project'] | null; // Project
|
||||
isFirstOpen: boolean; // Boolean!
|
||||
projects: NexusGenRootTypes['Project'][]; // [Project!]!
|
||||
user: NexusGenRootTypes['User'] | null; // User
|
||||
}
|
||||
Mutation: { // field return type
|
||||
addProject: NexusGenRootTypes['Project']; // Project!
|
||||
appCreateConfigFile: NexusGenRootTypes['App'] | null; // App
|
||||
authenticate: NexusGenRootTypes['App'] | null; // App
|
||||
initializePlugins: NexusGenRootTypes['Project'] | null; // Project
|
||||
logout: NexusGenRootTypes['App'] | null; // App
|
||||
wizardInstallDependencies: NexusGenRootTypes['Wizard'] | null; // Wizard
|
||||
wizardNavigate: NexusGenRootTypes['Wizard'] | null; // Wizard
|
||||
wizardNavigateForward: NexusGenRootTypes['Wizard'] | null; // Wizard
|
||||
@@ -125,6 +130,8 @@ export interface NexusGenFieldTypes {
|
||||
}
|
||||
Query: { // field return type
|
||||
app: NexusGenRootTypes['App']; // App!
|
||||
runs: NexusGenRootTypes['App'] | null; // App
|
||||
user: NexusGenRootTypes['User'] | null; // User
|
||||
wizard: NexusGenRootTypes['Wizard'] | null; // Wizard
|
||||
}
|
||||
TestingTypeInfo: { // field return type
|
||||
@@ -132,6 +139,11 @@ export interface NexusGenFieldTypes {
|
||||
id: NexusGenEnums['TestingTypeEnum']; // TestingTypeEnum!
|
||||
title: string | null; // String
|
||||
}
|
||||
User: { // field return type
|
||||
authToken: string | null; // String
|
||||
email: string | null; // String
|
||||
name: string | null; // String
|
||||
}
|
||||
Wizard: { // field return type
|
||||
allBundlers: NexusGenRootTypes['WizardBundler'][]; // [WizardBundler!]!
|
||||
bundler: NexusGenRootTypes['WizardBundler'] | null; // WizardBundler
|
||||
@@ -170,11 +182,14 @@ export interface NexusGenFieldTypeNames {
|
||||
activeProject: 'Project'
|
||||
isFirstOpen: 'Boolean'
|
||||
projects: 'Project'
|
||||
user: 'User'
|
||||
}
|
||||
Mutation: { // field return type name
|
||||
addProject: 'Project'
|
||||
appCreateConfigFile: 'App'
|
||||
authenticate: 'App'
|
||||
initializePlugins: 'Project'
|
||||
logout: 'App'
|
||||
wizardInstallDependencies: 'Wizard'
|
||||
wizardNavigate: 'Wizard'
|
||||
wizardNavigateForward: 'Wizard'
|
||||
@@ -195,6 +210,8 @@ export interface NexusGenFieldTypeNames {
|
||||
}
|
||||
Query: { // field return type name
|
||||
app: 'App'
|
||||
runs: 'App'
|
||||
user: 'User'
|
||||
wizard: 'Wizard'
|
||||
}
|
||||
TestingTypeInfo: { // field return type name
|
||||
@@ -202,6 +219,11 @@ export interface NexusGenFieldTypeNames {
|
||||
id: 'TestingTypeEnum'
|
||||
title: 'String'
|
||||
}
|
||||
User: { // field return type name
|
||||
authToken: 'String'
|
||||
email: 'String'
|
||||
name: 'String'
|
||||
}
|
||||
Wizard: { // field return type name
|
||||
allBundlers: 'WizardBundler'
|
||||
bundler: 'WizardBundler'
|
||||
@@ -260,6 +282,11 @@ export interface NexusGenArgTypes {
|
||||
type: NexusGenEnums['TestingTypeEnum']; // TestingTypeEnum!
|
||||
}
|
||||
}
|
||||
Query: {
|
||||
runs: { // args
|
||||
projectId: string; // String!
|
||||
}
|
||||
}
|
||||
Wizard: {
|
||||
sampleCode: { // args
|
||||
lang: NexusGenEnums['WizardCodeLanguage']; // WizardCodeLanguage!
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface TestSourceTypeLookup {
|
||||
Project: NexusGenObjects['Project'],
|
||||
Query: NexusGenObjects['Query'],
|
||||
TestingTypeInfo: NexusGenObjects['TestingTypeInfo'],
|
||||
User: NexusGenObjects['User'],
|
||||
Wizard: NexusGenObjects['Wizard'],
|
||||
WizardBundler: NexusGenObjects['WizardBundler'],
|
||||
WizardFrontendFramework: NexusGenObjects['WizardFrontendFramework'],
|
||||
@@ -25,6 +26,7 @@ export const testUnionType = unionType({
|
||||
'Project',
|
||||
'Query',
|
||||
'TestingTypeInfo',
|
||||
'User',
|
||||
'Wizard',
|
||||
'WizardBundler',
|
||||
'WizardFrontendFramework',
|
||||
|
||||
@@ -1,6 +1 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
spec: 'test/unit/**/*.spec.{js,ts,tsx,jsx}',
|
||||
require: path.resolve(__dirname, 'spec_helper.js'),
|
||||
}
|
||||
module.exports = {}
|
||||
|
||||
33
packages/graphql/test/integration/App.spec.ts
Normal file
33
packages/graphql/test/integration/App.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { expect } from 'chai'
|
||||
import { initGraphql, makeRequest, TestContext } from './utils'
|
||||
|
||||
describe('App', () => {
|
||||
describe('authenticate', () => {
|
||||
it('assigns a new user', async () => {
|
||||
const context = new TestContext()
|
||||
const { endpoint } = await initGraphql(context)
|
||||
|
||||
const result = await makeRequest(endpoint, `
|
||||
mutation Authenticate {
|
||||
authenticate {
|
||||
user {
|
||||
email
|
||||
name
|
||||
authToken
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
expect(result).to.eql({
|
||||
authenticate: {
|
||||
user: {
|
||||
email: 'test@cypress.io',
|
||||
name: 'cypress test',
|
||||
authToken: 'test-auth-token',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,70 +1,7 @@
|
||||
import type { NxsMutationArgs } from 'nexus-decorators'
|
||||
import snapshot from 'snap-shot-it'
|
||||
import { expect } from 'chai'
|
||||
import axios from 'axios'
|
||||
import { BaseActions, BaseContext, Project, Wizard } from '../../src'
|
||||
import { startGraphQLServer, closeGraphQLServer, setServerContext } from '../../src/server'
|
||||
|
||||
class TestActions extends BaseActions {
|
||||
installDependencies () {}
|
||||
createConfigFile () {}
|
||||
createProjectBase (input: NxsMutationArgs<'addProject'>['input']) {
|
||||
return new Project({
|
||||
isCurrent: true,
|
||||
projectRoot: '/foo/bar',
|
||||
projectBase: {
|
||||
isOpen: true,
|
||||
initializePlugins: () => Promise.resolve(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
interface TestContextInjectionOptions {
|
||||
wizard?: Wizard
|
||||
}
|
||||
|
||||
class TestContext extends BaseContext {
|
||||
projects: Project[] = []
|
||||
readonly actions: BaseActions
|
||||
|
||||
constructor ({ wizard }: TestContextInjectionOptions = {}) {
|
||||
super()
|
||||
this.actions = new TestActions(this)
|
||||
if (wizard) {
|
||||
this.wizard = wizard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GraphQL server to query during integration tests.
|
||||
* Also performsn any clean up from previous tests.
|
||||
* Optionally you may provide a context to orchestrate testing
|
||||
* specific scenarios or states.
|
||||
*/
|
||||
const initGraphql = async (ctx: BaseContext) => {
|
||||
await closeGraphQLServer()
|
||||
if (ctx) {
|
||||
setServerContext(ctx)
|
||||
}
|
||||
|
||||
return startGraphQLServer({ port: 51515 })
|
||||
}
|
||||
|
||||
const makeRequest = async (endpoint: string, query: string) => {
|
||||
const res = await axios.post(endpoint,
|
||||
JSON.stringify({
|
||||
query,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
return res.data.data
|
||||
}
|
||||
import { Wizard } from '../../src'
|
||||
import { initGraphql, makeRequest, TestContext } from './utils'
|
||||
|
||||
describe('Wizard', () => {
|
||||
describe('sampleCode', () => {
|
||||
|
||||
82
packages/graphql/test/integration/utils.ts
Normal file
82
packages/graphql/test/integration/utils.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { NxsMutationArgs } from 'nexus-decorators'
|
||||
import axios from 'axios'
|
||||
import { BaseActions, BaseContext, Project, User, Wizard } from '../../src'
|
||||
import { startGraphQLServer, closeGraphQLServer, setServerContext } from '../../src/server'
|
||||
|
||||
class TestActions extends BaseActions {
|
||||
async authenticate () {
|
||||
this.ctx.user = new User({
|
||||
authToken: 'test-auth-token',
|
||||
email: 'test@cypress.io',
|
||||
name: 'cypress test',
|
||||
})
|
||||
}
|
||||
|
||||
async getRuns ({ projectId }: { projectId: string }) {}
|
||||
|
||||
async logout () {
|
||||
this.ctx.user = undefined
|
||||
}
|
||||
|
||||
installDependencies () {}
|
||||
|
||||
createConfigFile () {}
|
||||
|
||||
createProjectBase (input: NxsMutationArgs<'addProject'>['input']) {
|
||||
return new Project({
|
||||
isCurrent: true,
|
||||
projectRoot: '/foo/bar',
|
||||
projectBase: {
|
||||
isOpen: true,
|
||||
initializePlugins: () => Promise.resolve(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
interface TestContextInjectionOptions {
|
||||
wizard?: Wizard
|
||||
}
|
||||
|
||||
export class TestContext extends BaseContext {
|
||||
projects: Project[] = []
|
||||
readonly actions: BaseActions
|
||||
user: undefined
|
||||
|
||||
constructor ({ wizard }: TestContextInjectionOptions = {}) {
|
||||
super()
|
||||
this.actions = new TestActions(this)
|
||||
if (wizard) {
|
||||
this.wizard = wizard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GraphQL server to query during integration tests.
|
||||
* Also performsn any clean up from previous tests.
|
||||
* Optionally you may provide a context to orchestrate testing
|
||||
* specific scenarios or states.
|
||||
*/
|
||||
export const initGraphql = async (ctx: BaseContext) => {
|
||||
await closeGraphQLServer()
|
||||
if (ctx) {
|
||||
setServerContext(ctx)
|
||||
}
|
||||
|
||||
return startGraphQLServer({ port: 51515 })
|
||||
}
|
||||
|
||||
export const makeRequest = async (endpoint: string, query: string) => {
|
||||
const res = await axios.post(endpoint,
|
||||
JSON.stringify({
|
||||
query,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
return res.data.data
|
||||
}
|
||||
70
packages/launchpad/src/setup/Auth.vue
Normal file
70
packages/launchpad/src/setup/Auth.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<Button @click="handleAuth">Click to Authenticate</Button>
|
||||
|
||||
<div v-if="error">An error occurred while authenticating: {{ error }}</div>
|
||||
|
||||
<div v-else-if="data?.user?.email">
|
||||
<p>
|
||||
Congrats {{ data?.user?.email }}, you authenticated with Cypress Cloud.
|
||||
</p>
|
||||
<Button @click="handleLogout">Log out</Button>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
Nothing here yet
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { gql } from "@urql/core"
|
||||
import { useMutation } from "@urql/vue"
|
||||
import { AuthenticateDocument, UserFragment, LogoutDocument } from '../generated/graphql'
|
||||
import Button from '../components/button/Button.vue'
|
||||
|
||||
gql`
|
||||
fragment User on App {
|
||||
user {
|
||||
email
|
||||
authToken
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
gql`
|
||||
mutation authenticate {
|
||||
authenticate {
|
||||
...User
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
gql`
|
||||
mutation Logout {
|
||||
logout {
|
||||
...User
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const authenticate = useMutation(AuthenticateDocument)
|
||||
const logout = useMutation(LogoutDocument)
|
||||
const error = ref<string>()
|
||||
|
||||
const handleAuth = async () => {
|
||||
const result = await authenticate.executeMutation({})
|
||||
error.value = result.error?.message ?? undefined
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
// clear this for good measure
|
||||
error.value = undefined
|
||||
await logout.executeMutation({})
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
gql?: UserFragment | null
|
||||
}>()
|
||||
|
||||
const data = computed(() => props.gql)
|
||||
</script>
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<template v-if="!loading && wizard">
|
||||
<Auth :gql="app" />
|
||||
<h1 class="text-3xl mt-12 text-center">{{ wizard.title }}</h1>
|
||||
<p class="text-center text-gray-400 my-2 mx-10" v-html="wizard.description" />
|
||||
<div class="mx-5">
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch, computed } from "vue";
|
||||
import Auth from './Auth.vue'
|
||||
import TestingType from "./TestingType.vue";
|
||||
import EnvironmentSetup from "./EnvironmentSetup.vue";
|
||||
import InstallDependencies from "./InstallDependencies.vue";
|
||||
@@ -39,6 +41,7 @@ query Wizard {
|
||||
app {
|
||||
isFirstOpen
|
||||
...ProjectRoot
|
||||
...User
|
||||
}
|
||||
wizard {
|
||||
step
|
||||
@@ -58,6 +61,7 @@ export default defineComponent({
|
||||
TestingType,
|
||||
EnvironmentSetup,
|
||||
InstallDependencies,
|
||||
Auth,
|
||||
ConfigFile,
|
||||
OpenBrowser,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
import type { NxsMutationArgs } from 'nexus-decorators'
|
||||
import { ProjectBase } from '../project-base'
|
||||
import type { ServerContext } from './ServerContext'
|
||||
import { BaseActions } from '@packages/graphql'
|
||||
import { AuthenticatedUser, BaseActions, User } from '@packages/graphql'
|
||||
|
||||
// @ts-ignore
|
||||
import user from '@packages/server/lib/user'
|
||||
|
||||
// @ts-ignore
|
||||
import auth from '@packages/server/lib/gui/auth'
|
||||
|
||||
// @ts-ignore
|
||||
import api from '@packages/server/lib/api'
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -22,4 +31,22 @@ export class ServerActions extends BaseActions {
|
||||
options: {},
|
||||
})
|
||||
}
|
||||
|
||||
async authenticate () {
|
||||
const user: AuthenticatedUser = await auth.start(() => {}, 'launchpad')
|
||||
|
||||
this.ctx.user = new User(user)
|
||||
}
|
||||
|
||||
async logout () {
|
||||
await user.logOut()
|
||||
this.ctx.user = undefined
|
||||
}
|
||||
|
||||
async getRuns ({ projectId }: { projectId: string }) {
|
||||
const runs = await api.getProjectRuns(projectId, this.ctx.user?.authToken)
|
||||
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log({ runs })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
import { ServerActions } from './ServerActions'
|
||||
import { Project, BaseContext } from '@packages/graphql'
|
||||
import { Project, BaseContext, User, AuthenticatedUser } from '@packages/graphql'
|
||||
|
||||
// @ts-ignore
|
||||
import user from '@packages/server/lib/user'
|
||||
|
||||
export class ServerContext extends BaseContext {
|
||||
readonly actions = new ServerActions(this)
|
||||
user?: User
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
|
||||
user.get().then((cachedUser: AuthenticatedUser) => {
|
||||
// cache returns empty object if user is undefined
|
||||
this.user = Object.keys(cachedUser).length > 0
|
||||
? new User(cachedUser)
|
||||
: undefined
|
||||
})
|
||||
}
|
||||
|
||||
projects: Project[] = []
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ServerActions } from '../ServerActions'
|
||||
|
||||
export class ServerContext extends BaseContext {
|
||||
readonly actions = new ServerActions(this)
|
||||
user: undefined
|
||||
|
||||
projects: Project[] = []
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface ProjectBaseContract {
|
||||
isOpen: boolean
|
||||
initializePlugins(): Promise<unknown>
|
||||
}
|
||||
@@ -40,7 +40,7 @@ const nullifyUnserializableValues = (obj) => {
|
||||
return null
|
||||
}
|
||||
|
||||
return val
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user