test-job-ci

This commit is contained in:
Untone 2023-11-28 21:04:51 +03:00
parent b6f9251350
commit ed3360d92b
17 changed files with 68 additions and 100 deletions

View File

@ -1,9 +1,30 @@
name: 'deploy' name: 'deploy'
on: [push] on:
push:
branches:
- main
jobs: jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm run check
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: test # Ensure 'test' job is completed before deploying
steps: steps:
- name: Cloning repo - name: Cloning repo
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -28,7 +28,7 @@ generates:
# Generate types for notifier # Generate types for notifier
src/graphql/schema/notifier.gen.ts: src/graphql/schema/notifier.gen.ts:
schema: 'http://notifier.discours.io' # FIXME: https schema: 'https://notifier.discours.io' # FIXME: https
plugins: plugins:
- 'typescript' - 'typescript'
- 'typescript-operations' - 'typescript-operations'

View File

@ -3,9 +3,9 @@ import type { AuthModalSearchParams } from './types'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { createSignal, JSX, Show } from 'solid-js' import { createSignal, JSX, Show } from 'solid-js'
import { useAuthorizer } from '../../../context/authorizer'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { ApiError } from '../../../graphql/error' import { ApiError } from '../../../graphql/error'
import { signSendLink } from '../../../stores/auth'
import { useRouter } from '../../../stores/router' import { useRouter } from '../../../stores/router'
import { validateEmail } from '../../../utils/validateEmail' import { validateEmail } from '../../../utils/validateEmail'
@ -21,12 +21,12 @@ type ValidationErrors = Partial<Record<keyof FormFields, string | JSX.Element>>
export const ForgotPasswordForm = () => { export const ForgotPasswordForm = () => {
const { changeSearchParam } = useRouter<AuthModalSearchParams>() const { changeSearchParam } = useRouter<AuthModalSearchParams>()
const { t, lang } = useLocalize() const { t } = useLocalize()
const handleEmailInput = (newEmail: string) => { const handleEmailInput = (newEmail: string) => {
setValidationErrors(({ email: _notNeeded, ...rest }) => rest) setValidationErrors(({ email: _notNeeded, ...rest }) => rest)
setEmail(newEmail) setEmail(newEmail)
} }
const [, { authorizer }] = useAuthorizer()
const [submitError, setSubmitError] = createSignal('') const [submitError, setSubmitError] = createSignal('')
const [isSubmitting, setIsSubmitting] = createSignal(false) const [isSubmitting, setIsSubmitting] = createSignal(false)
const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({}) const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({})
@ -63,7 +63,10 @@ export const ForgotPasswordForm = () => {
setIsSubmitting(true) setIsSubmitting(true)
try { try {
await signSendLink({ email: email(), lang: lang(), template: 'forgot_password' }) const response = await authorizer().forgotPassword({ email: email() })
if (response) {
console.debug(response)
}
} catch (error) { } catch (error) {
if (error instanceof ApiError && error.code === 'user_not_found') { if (error instanceof ApiError && error.code === 'user_not_found') {
setIsUserNotFound(true) setIsUserNotFound(true)

View File

@ -3,11 +3,11 @@ import type { AuthModalSearchParams } from './types'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { createSignal, Show } from 'solid-js' import { createSignal, Show } from 'solid-js'
import { useAuthorizer } from '../../../context/authorizer'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'
import { useSnackbar } from '../../../context/snackbar' import { useSnackbar } from '../../../context/snackbar'
import { ApiError } from '../../../graphql/error' import { ApiError } from '../../../graphql/error'
import { signSendLink } from '../../../stores/auth'
import { useRouter } from '../../../stores/router' import { useRouter } from '../../../stores/router'
import { hideModal } from '../../../stores/ui' import { hideModal } from '../../../stores/ui'
import { validateEmail } from '../../../utils/validateEmail' import { validateEmail } from '../../../utils/validateEmail'
@ -27,7 +27,7 @@ type FormFields = {
type ValidationErrors = Partial<Record<keyof FormFields, string>> type ValidationErrors = Partial<Record<keyof FormFields, string>>
export const LoginForm = () => { export const LoginForm = () => {
const { t, lang } = useLocalize() const { t } = useLocalize()
const [submitError, setSubmitError] = createSignal('') const [submitError, setSubmitError] = createSignal('')
const [isSubmitting, setIsSubmitting] = createSignal(false) const [isSubmitting, setIsSubmitting] = createSignal(false)
@ -67,9 +67,9 @@ export const LoginForm = () => {
setIsLinkSent(true) setIsLinkSent(true)
setIsEmailNotConfirmed(false) setIsEmailNotConfirmed(false)
setSubmitError('') setSubmitError('')
const [{ token }, { authorizer }] = useAuthorizer()
const result = await signSendLink({ email: email(), lang: lang(), template: 'email_confirmation' }) const result = await authorizer().verifyEmail({ token: token.id_token })
if (result.error) setSubmitError(result.error) if (!result) setSubmitError('cant sign send link') // TODO:
} }
const handleSubmit = async (event: Event) => { const handleSubmit = async (event: Event) => {

View File

@ -4,9 +4,9 @@ import type { JSX } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { Show, createSignal } from 'solid-js' import { Show, createSignal } from 'solid-js'
import { useAuthorizer } from '../../../context/authorizer'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { ApiError } from '../../../graphql/error' import { ApiError } from '../../../graphql/error'
import { register } from '../../../stores/auth'
import { checkEmail, useEmailChecks } from '../../../stores/emailChecks' import { checkEmail, useEmailChecks } from '../../../stores/emailChecks'
import { useRouter } from '../../../stores/router' import { useRouter } from '../../../stores/router'
import { hideModal } from '../../../stores/ui' import { hideModal } from '../../../stores/ui'
@ -35,7 +35,7 @@ export const RegisterForm = () => {
const { changeSearchParam } = useRouter<AuthModalSearchParams>() const { changeSearchParam } = useRouter<AuthModalSearchParams>()
const { t } = useLocalize() const { t } = useLocalize()
const { emailChecks } = useEmailChecks() const { emailChecks } = useEmailChecks()
const [, { authorizer }] = useAuthorizer()
const [submitError, setSubmitError] = createSignal('') const [submitError, setSubmitError] = createSignal('')
const [fullName, setFullName] = createSignal('') const [fullName, setFullName] = createSignal('')
const [password, setPassword] = createSignal('') const [password, setPassword] = createSignal('')
@ -127,10 +127,11 @@ export const RegisterForm = () => {
setIsSubmitting(true) setIsSubmitting(true)
try { try {
await register({ await authorizer().signup({
name: cleanName, given_name: cleanName,
email: cleanEmail, email: cleanEmail,
password: password(), password: password(),
confirm_password: password(),
}) })
setIsSuccess(true) setIsSuccess(true)

View File

@ -6,7 +6,7 @@ import { createMemo, createSignal, onMount, Show } from 'solid-js'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useNotifications } from '../../../context/notifications' import { useNotifications } from '../../../context/notifications'
import { Reaction, Shout } from '../../../graphql/schema/core.gen' import { Reaction } from '../../../graphql/schema/core.gen'
import { Notification } from '../../../graphql/schema/notifier.gen' import { Notification } from '../../../graphql/schema/notifier.gen'
import { router, useRouter } from '../../../stores/router' import { router, useRouter } from '../../../stores/router'
import { GroupAvatar } from '../../_shared/GroupAvatar' import { GroupAvatar } from '../../_shared/GroupAvatar'
@ -111,17 +111,6 @@ export const NotificationView = (props: Props) => {
) )
} }
} }
case 'update':
case 'delete':
case 'follow':
case 'unfollow':
case 'invited':
// TODO: invited for collaborative authoring
default: { default: {
return <></> return <></>
} }

View File

@ -38,7 +38,7 @@ const shorten = (str: string, maxLen: number) => {
export const PublishSettings = async (props: Props) => { export const PublishSettings = async (props: Props) => {
const { t } = useLocalize() const { t } = useLocalize()
const { session, author } = useSession() const { author } = useSession()
const composeDescription = () => { const composeDescription = () => {
if (!props.form.description) { if (!props.form.description) {

View File

@ -1,14 +1,14 @@
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { For } from 'solid-js' import { For } from 'solid-js'
import { Author } from '../../../graphql/schema/core.gen'
import { Userpic } from '../../Author/Userpic' import { Userpic } from '../../Author/Userpic'
import { NotificationUser } from '../../NotificationsPanel/NotificationView/NotificationView'
import styles from './GroupAvatar.module.scss' import styles from './GroupAvatar.module.scss'
type Props = { type Props = {
class?: string class?: string
authors: NotificationUser[] authors: Author[]
} }
export const GroupAvatar = (props: Props) => { export const GroupAvatar = (props: Props) => {
@ -35,8 +35,8 @@ export const GroupAvatar = (props: Props) => {
})} })}
> >
<For each={displayedAvatars}> <For each={displayedAvatars}>
{(user) => ( {(author: Author) => (
<Userpic size={avatarSize()} name={user.name} userpic={user.userpic} class={styles.item} /> <Userpic size={avatarSize()} name={author.name} userpic={author.pic} class={styles.item} />
)} )}
</For> </For>
{props.authors.length > 4 && <div class={styles.moreUsers}>+{props.authors?.length - 3}</div>} {props.authors.length > 4 && <div class={styles.moreUsers}>+{props.authors?.length - 3}</div>}

View File

@ -142,7 +142,7 @@ export const AuthorizerProvider: ParentComponent<AuthorizerProviderProps> = (pro
} catch { } catch {
setState((prev) => ({ ...prev, user: null, token: null })) setState((prev) => ({ ...prev, user: null, token: null }))
} finally { } finally {
setState('config', (config) => ({ ...config, ...metaRes })) setState('config', (cfg) => ({ ...cfg, ...metaRes }))
setState('loading', false) setState('loading', false)
} }
} }

View File

@ -1,10 +1,10 @@
import type { ProfileInput } from '../graphql/schema/core.gen' import type { ProfileInput } from '../graphql/schema/core.gen'
import { createEffect, createMemo, createSignal } from 'solid-js' import { createEffect, createSignal } from 'solid-js'
import { createStore } from 'solid-js/store' import { createStore } from 'solid-js/store'
import { apiClient } from '../graphql/client/core' import { apiClient } from '../graphql/client/core'
import { loadAuthor, useAuthorsStore } from '../stores/zine/authors' import { loadAuthor } from '../stores/zine/authors'
import { useSession } from './session' import { useSession } from './session'
@ -15,8 +15,7 @@ const userpicUrl = (userpic: string) => {
return userpic return userpic
} }
const useProfileForm = () => { const useProfileForm = () => {
const { session } = useSession() const { author: currentAuthor } = useSession()
const currentAuthor = createMemo(() => session()?.author)
const [slugError, setSlugError] = createSignal<string>() const [slugError, setSlugError] = createSignal<string>()
const submit = async (profile: ProfileInput) => { const submit = async (profile: ProfileInput) => {

View File

@ -3,18 +3,10 @@ import type { Author, Result } from '../graphql/schema/core.gen'
import type { Accessor, JSX, Resource } from 'solid-js' import type { Accessor, JSX, Resource } from 'solid-js'
import { VerifyEmailInput, LoginInput, AuthToken, User } from '@authorizerdev/authorizer-js' import { VerifyEmailInput, LoginInput, AuthToken, User } from '@authorizerdev/authorizer-js'
import { import { createContext, createMemo, createResource, createSignal, onMount, useContext } from 'solid-js'
createEffect,
createContext,
createMemo,
createResource,
createSignal,
onMount,
useContext,
} from 'solid-js'
import { apiClient } from '../graphql/client/core' import { apiClient } from '../graphql/client/core'
import { getToken, resetToken, setToken } from '../graphql/privateGraphQLClient' import { getToken, resetToken } from '../graphql/privateGraphQLClient'
import { showModal } from '../stores/ui' import { showModal } from '../stores/ui'
import { useAuthorizer } from './authorizer' import { useAuthorizer } from './authorizer'
@ -75,7 +67,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
try { try {
const token = getToken() // FIXME: token in localStorage? const token = getToken() // FIXME: token in localStorage?
const authResult = await authorizer().getSession({ const authResult = await authorizer().getSession({
Authorization: token, Authorization: token, // authToken()
}) })
if (authResult) { if (authResult) {
console.log(authResult) console.log(authResult)
@ -105,9 +97,9 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
const [author, { refetch: loadAuthor }] = createResource<Author | null>( const [author, { refetch: loadAuthor }] = createResource<Author | null>(
async () => { async () => {
const user = session()?.user const u = session()?.user
if (user) { if (u) {
return (await apiClient.getAuthor({ user: user.id })) ?? null return (await apiClient.getAuthor({ user: u.id })) ?? null
} }
return null return null
}, },
@ -126,7 +118,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
mutate(authResult) mutate(authResult)
} }
loadSubscriptions() loadSubscriptions()
// console.debug('signed in') console.debug('signed in')
} }
const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null) const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null)
@ -156,10 +148,10 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
} }
const confirmEmail = async (input: VerifyEmailInput) => { const confirmEmail = async (input: VerifyEmailInput) => {
const authToken: void | AuthToken = await authorizer().verifyEmail(input) const at: void | AuthToken = await authorizer().verifyEmail(input)
if (authToken) { if (at) {
setToken(authToken.access_token) setToken(at.access_token)
mutate(authToken) mutate(at)
} }
} }

View File

@ -2,7 +2,7 @@ import markAllNotificationsAsRead from '../mutation/notifier/mark-all-notificati
import markNotificationAsRead from '../mutation/notifier/mark-notification-as-read' import markNotificationAsRead from '../mutation/notifier/mark-notification-as-read'
import { getPrivateClient } from '../privateGraphQLClient' import { getPrivateClient } from '../privateGraphQLClient'
import loadNotifications from '../query/notifier/notifications-load' import loadNotifications from '../query/notifier/notifications-load'
import { Notification, NotificationsResult, QueryLoad_NotificationsArgs } from '../schema/notifier.gen' import { NotificationsResult, QueryLoad_NotificationsArgs } from '../schema/notifier.gen'
export const notifierPrivateGraphqlClient = getPrivateClient('notifier') export const notifierPrivateGraphqlClient = getPrivateClient('notifier')

View File

@ -1,7 +1,7 @@
import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core' import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core'
import { devtoolsExchange } from '@urql/devtools' import { devtoolsExchange } from '@urql/devtools'
import { isDev, apiBaseUrl } from '../utils/config' import { isDev } from '../utils/config'
const TOKEN_LOCAL_STORAGE_KEY = 'token' const TOKEN_LOCAL_STORAGE_KEY = 'token'
@ -28,7 +28,7 @@ export const resetToken = () => {
} }
const options: ClientOptions = { const options: ClientOptions = {
url: apiBaseUrl, url: '',
maskTypename: true, maskTypename: true,
requestPolicy: 'cache-and-network', requestPolicy: 'cache-and-network',
fetchOptions: () => { fetchOptions: () => {

View File

@ -1,7 +1,7 @@
import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core' import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core'
import { devtoolsExchange } from '@urql/devtools' import { devtoolsExchange } from '@urql/devtools'
import { isDev, apiBaseUrl } from '../utils/config' import { isDev } from '../utils/config'
// import { cache } from './cache' // import { cache } from './cache'
const exchanges: Exchange[] = [dedupExchange, fetchExchange] //, cache] const exchanges: Exchange[] = [dedupExchange, fetchExchange] //, cache]
@ -11,7 +11,7 @@ if (isDev) {
} }
const options: ClientOptions = { const options: ClientOptions = {
url: apiBaseUrl, url: '',
maskTypename: true, maskTypename: true,
requestPolicy: 'cache-and-network', requestPolicy: 'cache-and-network',
exchanges, exchanges,

View File

@ -1,33 +0,0 @@
import { MagicLinkLoginInput, SignupInput } from '@authorizerdev/authorizer-js'
import { useAuthorizer } from '../context/authorizer'
const [, { authorizer }] = useAuthorizer()
export const register = async ({
name,
email,
password,
}: {
name: string
email: string
password: string
}) => {
const signupInput: SignupInput = {
email,
password,
confirm_password: password,
}
await authorizer().signup(signupInput)
}
export const signSendLink = async ({
email,
lang,
template,
}: {
email: string
lang: string
template: string
}) => {
return await authorizer().magicLinkLogin({ email } as MagicLinkLoginInput)
}

View File

@ -2,8 +2,8 @@ import { createLazyMemo } from '@solid-primitives/memo'
import { createSignal } from 'solid-js' import { createSignal } from 'solid-js'
import { apiClient } from '../../graphql/client/core' import { apiClient } from '../../graphql/client/core'
import { byStat } from '../../utils/sortby'
import { Author } from '../../graphql/schema/core.gen' import { Author } from '../../graphql/schema/core.gen'
import { byStat } from '../../utils/sortby'
export type AuthorsSortBy = 'shouts' | 'name' | 'followers' export type AuthorsSortBy = 'shouts' | 'name' | 'followers'

View File

@ -1,9 +1,5 @@
export const isDev = import.meta.env.MODE === 'development' export const isDev = import.meta.env.MODE === 'development'
const defaultApiUrl = 'https://testapi.discours.io'
// export const apiBaseUrl = import.meta.env.PUBLIC_API_URL || defaultApiUrl
export const apiBaseUrl = 'https://v2.discours.io'
const defaultThumborUrl = 'https://images.discours.io' const defaultThumborUrl = 'https://images.discours.io'
export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl export const thumborUrl = import.meta.env.PUBLIC_THUMBOR_URL || defaultThumborUrl